summaryrefslogtreecommitdiff
path: root/libnitrokey-3.3/libnitrokey
diff options
context:
space:
mode:
Diffstat (limited to 'libnitrokey-3.3/libnitrokey')
-rw-r--r--libnitrokey-3.3/libnitrokey/CommandFailedException.h76
-rw-r--r--libnitrokey-3.3/libnitrokey/DeviceCommunicationExceptions.h73
-rw-r--r--libnitrokey-3.3/libnitrokey/LibraryException.h118
-rw-r--r--libnitrokey-3.3/libnitrokey/LongOperationInProgressException.h45
-rw-r--r--libnitrokey-3.3/libnitrokey/NitrokeyManager.h284
-rw-r--r--libnitrokey-3.3/libnitrokey/command.h112
-rw-r--r--libnitrokey-3.3/libnitrokey/command_id.h152
-rw-r--r--libnitrokey-3.3/libnitrokey/cxx_semantics.h44
-rw-r--r--libnitrokey-3.3/libnitrokey/device.h169
-rw-r--r--libnitrokey-3.3/libnitrokey/device_proto.h491
-rw-r--r--libnitrokey-3.3/libnitrokey/dissect.h145
-rw-r--r--libnitrokey-3.3/libnitrokey/hidapi/hidapi.h391
-rw-r--r--libnitrokey-3.3/libnitrokey/log.h108
-rw-r--r--libnitrokey-3.3/libnitrokey/misc.h94
-rw-r--r--libnitrokey-3.3/libnitrokey/stick10_commands.h889
-rw-r--r--libnitrokey-3.3/libnitrokey/stick10_commands_0.8.h348
-rw-r--r--libnitrokey-3.3/libnitrokey/stick20_commands.h388
17 files changed, 3927 insertions, 0 deletions
diff --git a/libnitrokey-3.3/libnitrokey/CommandFailedException.h b/libnitrokey-3.3/libnitrokey/CommandFailedException.h
new file mode 100644
index 0000000..32bd6b7
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/CommandFailedException.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef LIBNITROKEY_COMMANDFAILEDEXCEPTION_H
+#define LIBNITROKEY_COMMANDFAILEDEXCEPTION_H
+
+#include <exception>
+#include <cstdint>
+#include "log.h"
+#include "command_id.h"
+
+using cs = nitrokey::proto::stick10::command_status;
+using cs2 = nitrokey::proto::stick20::device_status;
+
+class CommandFailedException : public std::exception {
+public:
+ const uint8_t last_command_id;
+ const uint8_t last_command_status;
+
+ CommandFailedException(uint8_t last_command_id, uint8_t last_command_status) :
+ last_command_id(last_command_id),
+ last_command_status(last_command_status){
+ LOG(std::string("CommandFailedException, status: ")+ std::to_string(last_command_status), nitrokey::log::Loglevel::DEBUG);
+ }
+
+ virtual const char *what() const throw() {
+ return "Command execution has failed on device";
+ }
+
+
+ bool reason_timestamp_warning() const throw(){
+ return last_command_status == static_cast<uint8_t>(cs::timestamp_warning);
+ }
+
+ bool reason_AES_not_initialized() const throw(){
+ return last_command_status == static_cast<uint8_t>(cs::AES_dec_failed);
+ }
+
+ bool reason_not_authorized() const throw(){
+ return last_command_status == static_cast<uint8_t>(cs::not_authorized);
+ }
+
+ bool reason_slot_not_programmed() const throw(){
+ return last_command_status == static_cast<uint8_t>(cs::slot_not_programmed);
+ }
+
+ bool reason_wrong_password() const throw(){
+ return last_command_status == static_cast<uint8_t>(cs::wrong_password);
+ }
+
+ bool reason_smartcard_busy() const throw(){
+ return last_command_status == static_cast<uint8_t>(cs2::smartcard_error);
+ }
+
+};
+
+
+#endif //LIBNITROKEY_COMMANDFAILEDEXCEPTION_H
diff --git a/libnitrokey-3.3/libnitrokey/DeviceCommunicationExceptions.h b/libnitrokey-3.3/libnitrokey/DeviceCommunicationExceptions.h
new file mode 100644
index 0000000..f710d0b
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/DeviceCommunicationExceptions.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+
+#ifndef LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H
+#define LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H
+
+#include <atomic>
+#include <exception>
+#include <stdexcept>
+#include <string>
+
+
+class DeviceCommunicationException: public std::runtime_error
+{
+ std::string message;
+ static std::atomic_int occurred;
+public:
+ DeviceCommunicationException(std::string _msg): std::runtime_error(_msg), message(_msg){
+ ++occurred;
+ }
+ uint8_t getType() const {return 1;};
+// virtual const char* what() const throw() override {
+// return message.c_str();
+// }
+ static bool has_occurred(){ return occurred > 0; };
+ static void reset_occurred_flag(){ occurred = 0; };
+};
+
+class DeviceNotConnected: public DeviceCommunicationException {
+public:
+ DeviceNotConnected(std::string msg) : DeviceCommunicationException(msg){}
+ uint8_t getType() const {return 2;};
+};
+
+class DeviceSendingFailure: public DeviceCommunicationException {
+public:
+ DeviceSendingFailure(std::string msg) : DeviceCommunicationException(msg){}
+ uint8_t getType() const {return 3;};
+};
+
+class DeviceReceivingFailure: public DeviceCommunicationException {
+public:
+ DeviceReceivingFailure(std::string msg) : DeviceCommunicationException(msg){}
+ uint8_t getType() const {return 4;};
+};
+
+class InvalidCRCReceived: public DeviceReceivingFailure {
+public:
+ InvalidCRCReceived(std::string msg) : DeviceReceivingFailure(msg){}
+ uint8_t getType() const {return 5;};
+};
+
+
+#endif //LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H
diff --git a/libnitrokey-3.3/libnitrokey/LibraryException.h b/libnitrokey-3.3/libnitrokey/LibraryException.h
new file mode 100644
index 0000000..3b9d177
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/LibraryException.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef LIBNITROKEY_LIBRARYEXCEPTION_H
+#define LIBNITROKEY_LIBRARYEXCEPTION_H
+
+#include <exception>
+#include <cstdint>
+#include <string>
+#include "log.h"
+
+class LibraryException: std::exception {
+public:
+ virtual uint8_t exception_id()= 0;
+};
+
+class TargetBufferSmallerThanSource: public LibraryException {
+public:
+ virtual uint8_t exception_id() override {
+ return 203;
+ }
+
+public:
+ size_t source_size;
+ size_t target_size;
+
+ TargetBufferSmallerThanSource(
+ size_t source_size, size_t target_size
+ ) : source_size(source_size), target_size(target_size) {}
+
+ virtual const char *what() const throw() override {
+ std::string s = " ";
+ auto ts = [](size_t x){ return std::to_string(x); };
+ std::string msg = std::string("Target buffer size is smaller than source: [source size, buffer size]")
+ +s+ ts(source_size) +s+ ts(target_size);
+ return msg.c_str();
+ }
+
+};
+
+class InvalidHexString : public LibraryException {
+public:
+ virtual uint8_t exception_id() override {
+ return 202;
+ }
+
+public:
+ uint8_t invalid_char;
+
+ InvalidHexString (uint8_t invalid_char) : invalid_char( invalid_char) {}
+
+ virtual const char *what() const throw() override {
+ return "Invalid character in hex string";
+ }
+
+};
+
+class InvalidSlotException : public LibraryException {
+public:
+ virtual uint8_t exception_id() override {
+ return 201;
+ }
+
+public:
+ uint8_t slot_selected;
+
+ InvalidSlotException(uint8_t slot_selected) : slot_selected(slot_selected) {}
+
+ virtual const char *what() const throw() override {
+ return "Wrong slot selected";
+ }
+
+};
+
+
+
+class TooLongStringException : public LibraryException {
+public:
+ virtual uint8_t exception_id() override {
+ return 200;
+ }
+
+ std::size_t size_source;
+ std::size_t size_destination;
+ std::string message;
+
+ TooLongStringException(size_t size_source, size_t size_destination, const std::string &message = "") : size_source(
+ size_source), size_destination(size_destination), message(message) {
+ LOG(std::string("TooLongStringException, size diff: ")+ std::to_string(size_source-size_destination), nitrokey::log::Loglevel::DEBUG);
+
+ }
+
+ virtual const char *what() const throw() override {
+ //TODO add sizes and message data to final message
+ return "Too long string has been supplied as an argument";
+ }
+
+};
+
+#endif //LIBNITROKEY_LIBRARYEXCEPTION_H
diff --git a/libnitrokey-3.3/libnitrokey/LongOperationInProgressException.h b/libnitrokey-3.3/libnitrokey/LongOperationInProgressException.h
new file mode 100644
index 0000000..865d6b5
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/LongOperationInProgressException.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H
+#define LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H
+
+#include "CommandFailedException.h"
+
+class LongOperationInProgressException : public CommandFailedException {
+
+public:
+ unsigned char progress_bar_value;
+
+ LongOperationInProgressException(
+ unsigned char _command_id, uint8_t last_command_status, unsigned char _progress_bar_value)
+ : CommandFailedException(_command_id, last_command_status), progress_bar_value(_progress_bar_value){
+ LOG(
+ std::string("LongOperationInProgressException, progress bar status: ")+
+ std::to_string(progress_bar_value), nitrokey::log::Loglevel::DEBUG);
+ }
+ virtual const char *what() const throw() {
+ return "Device returned busy status with long operation in progress";
+ }
+};
+
+
+#endif //LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H
diff --git a/libnitrokey-3.3/libnitrokey/NitrokeyManager.h b/libnitrokey-3.3/libnitrokey/NitrokeyManager.h
new file mode 100644
index 0000000..1f4cec4
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/NitrokeyManager.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef LIBNITROKEY_NITROKEYMANAGER_H
+#define LIBNITROKEY_NITROKEYMANAGER_H
+
+#include "device.h"
+#include "log.h"
+#include "device_proto.h"
+#include "stick10_commands.h"
+#include "stick10_commands_0.8.h"
+#include "stick20_commands.h"
+#include <vector>
+#include <memory>
+#include <unordered_map>
+
+namespace nitrokey {
+ using namespace nitrokey::device;
+ using namespace std;
+ using namespace nitrokey::proto::stick10;
+ using namespace nitrokey::proto::stick20;
+ using namespace nitrokey::proto;
+ using namespace nitrokey::log;
+
+
+#ifdef __WIN32
+char * strndup(const char* str, size_t maxlen);
+#endif
+
+ class NitrokeyManager {
+ public:
+ static shared_ptr <NitrokeyManager> instance();
+
+ bool first_authenticate(const char *pin, const char *temporary_password);
+ bool 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);
+ bool 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);
+ string get_HOTP_code(uint8_t slot_number, const char *user_temporary_password);
+ string get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time,
+ uint8_t last_interval,
+ const char *user_temporary_password);
+ string get_TOTP_code(uint8_t slot_number, const char *user_temporary_password);
+ stick10::ReadSlot::ResponsePayload get_TOTP_slot_data(const uint8_t slot_number);
+ stick10::ReadSlot::ResponsePayload get_HOTP_slot_data(const uint8_t slot_number);
+
+ bool set_time(uint64_t time);
+ bool get_time(uint64_t time = 0);
+ bool erase_totp_slot(uint8_t slot_number, const char *temporary_password);
+ bool erase_hotp_slot(uint8_t slot_number, const char *temporary_password);
+ std::vector<std::string> list_devices();
+ std::vector<std::string> list_devices_by_cpuID();
+
+ /**
+ * Connect to the device using unique smartcard:datacard id.
+ * Needs list_device_by_cpuID() run first
+ * @param id Current ID of the target device
+ * @return true on success, false on failure
+ */
+ bool connect_with_ID(const std::string id);
+ bool connect_with_path (std::string path);
+ bool connect(const char *device_model);
+ bool connect(device::DeviceModel device_model);
+ bool connect();
+ bool disconnect();
+ bool is_connected() throw() ;
+ bool could_current_device_be_enumerated();
+ bool set_default_commands_delay(int delay);
+
+ DeviceModel get_connected_device_model() const;
+ void set_debug(bool state);
+ stick10::GetStatus::ResponsePayload get_status();
+ string get_status_as_string();
+ string get_serial_number();
+
+ const char * get_totp_slot_name(uint8_t slot_number);
+ const char * get_hotp_slot_name(uint8_t slot_number);
+
+ void change_user_PIN(const char *current_PIN, const char *new_PIN);
+ void change_admin_PIN(const char *current_PIN, const char *new_PIN);
+
+ void enable_password_safe(const char *user_pin);
+
+ vector <uint8_t> get_password_safe_slot_status();
+
+ uint8_t get_admin_retry_count();
+ uint8_t get_user_retry_count();
+
+ void lock_device();
+
+ const char *get_password_safe_slot_name(uint8_t slot_number);
+ const char *get_password_safe_slot_password(uint8_t slot_number);
+ const char *get_password_safe_slot_login(uint8_t slot_number);
+
+ void
+ write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login,
+ const char *slot_password);
+
+ void erase_password_safe_slot(uint8_t slot_number);
+
+ void user_authenticate(const char *user_password, const char *temporary_password);
+
+ void factory_reset(const char *admin_password);
+
+ void build_aes_key(const char *admin_password);
+
+ void unlock_user_password(const char *admin_password, const char *new_user_password);
+
+ void write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password,
+ bool delete_user_password, const char *admin_temporary_password);
+
+ vector<uint8_t> read_config();
+
+ bool is_AES_supported(const char *user_password);
+
+ void unlock_encrypted_volume(const char *user_password);
+ void lock_encrypted_volume();
+
+ void unlock_hidden_volume(const char *hidden_volume_password);
+ void lock_hidden_volume();
+
+ /**
+ * Sets unencrypted volume read-only.
+ * Works until v0.48 (incl. v0.50), where User PIN was sufficient
+ * Does nothing otherwise.
+ * @param user_pin User PIN
+ */
+ void set_unencrypted_read_only(const char *user_pin);
+
+ /**
+ * Sets unencrypted volume read-only.
+ * Works from v0.49 (except v0.50) accepts Admin PIN
+ * Does nothing otherwise.
+ * @param admin_pin Admin PIN
+ */
+ void set_unencrypted_read_only_admin(const char *admin_pin);
+
+ /**
+ * Sets unencrypted volume read-write.
+ * Works until v0.48 (incl. v0.50), where User PIN was sufficient
+ * Does nothing otherwise.
+ * @param user_pin User PIN
+ */
+ void set_unencrypted_read_write(const char *user_pin);
+
+ /**
+ * Sets unencrypted volume read-write.
+ * Works from v0.49 (except v0.50) accepts Admin PIN
+ * Does nothing otherwise.
+ * @param admin_pin Admin PIN
+ */
+ void set_unencrypted_read_write_admin(const char *admin_pin);
+
+ void export_firmware(const char *admin_pin);
+ void enable_firmware_update(const char *firmware_pin);
+
+ void clear_new_sd_card_warning(const char *admin_pin);
+
+ void fill_SD_card_with_random_data(const char *admin_pin);
+
+ uint8_t get_SD_card_size();
+
+ void change_update_password(const char *current_update_password, const char *new_update_password);
+
+ void create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent,
+ const char *hidden_volume_password);
+
+ void send_startup(uint64_t seconds_from_epoch);
+
+ const char * get_status_storage_as_string();
+ stick20::DeviceConfigurationResponsePacket::ResponsePayload get_status_storage();
+
+ const char *get_SD_usage_data_as_string();
+ std::pair<uint8_t,uint8_t> get_SD_usage_data();
+
+
+ int get_progress_bar_value();
+
+ ~NitrokeyManager();
+ bool is_authorization_command_supported();
+ bool is_320_OTP_secret_supported();
+
+
+ template <typename S, typename A, typename T>
+ void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr<Device> device);
+ int get_minor_firmware_version();
+
+ explicit NitrokeyManager();
+ void set_log_function(std::function<void(std::string)> log_function);
+ private:
+
+ static shared_ptr <NitrokeyManager> _instance;
+ std::shared_ptr<Device> device;
+ std::string current_device_id;
+ public:
+ const string get_current_device_id() const;
+
+ private:
+ std::unordered_map<std::string, shared_ptr<Device> > connected_devices;
+ std::unordered_map<std::string, shared_ptr<Device> > connected_devices_byID;
+
+
+ stick10::ReadSlot::ResponsePayload get_OTP_slot_data(const uint8_t slot_number);
+ bool is_valid_hotp_slot_number(uint8_t slot_number) const;
+ bool is_valid_totp_slot_number(uint8_t slot_number) const;
+ bool is_valid_password_safe_slot_number(uint8_t slot_number) const;
+ uint8_t get_internal_slot_number_for_hotp(uint8_t slot_number) const;
+ uint8_t get_internal_slot_number_for_totp(uint8_t slot_number) const;
+ bool erase_slot(uint8_t slot_number, const char *temporary_password);
+ const char * get_slot_name(uint8_t slot_number);
+
+ template <typename ProCommand, PasswordKind StoKind>
+ void change_PIN_general(const char *current_PIN, const 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_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_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;
+ bool _disconnect_no_lock();
+
+ public:
+ bool set_current_device_speed(int retry_delay, int send_receive_delay);
+ void set_loglevel(Loglevel loglevel);
+
+ void set_loglevel(int loglevel);
+
+ /**
+ * Sets encrypted volume read-only.
+ * Supported from future versions of Storage.
+ * @param admin_pin Admin PIN
+ */
+ void set_encrypted_volume_read_only(const char *admin_pin);
+
+ /**
+ * Sets encrypted volume read-write.
+ * Supported from future versions of Storage.
+ * @param admin_pin Admin PIN
+ */
+ void set_encrypted_volume_read_write(const char *admin_pin);
+
+ int get_major_firmware_version();
+
+ bool is_smartcard_in_use();
+
+ /**
+ * Function to determine unencrypted volume PIN type
+ * @param minor_firmware_version
+ * @return Returns true, if set unencrypted volume ro/rw pin type is User, false otherwise.
+ */
+ bool set_unencrypted_volume_rorw_pin_type_user();
+ };
+}
+
+
+
+#endif //LIBNITROKEY_NITROKEYMANAGER_H
diff --git a/libnitrokey-3.3/libnitrokey/command.h b/libnitrokey-3.3/libnitrokey/command.h
new file mode 100644
index 0000000..6852bf0
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/command.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef COMMAND_H
+#define COMMAND_H
+#include <string>
+#include "command_id.h"
+#include "cxx_semantics.h"
+
+#define print_to_ss(x) ( ss << " " << (#x) <<":\t" << (x) << std::endl );
+#ifdef LOG_VOLATILE_DATA
+#define print_to_ss_volatile(x) print_to_ss(x);
+#else
+#define print_to_ss_volatile(x) ( ss << " " << (#x) <<":\t" << "***********" << std::endl );
+#endif
+#define hexdump_to_ss(x) (ss << #x":\n"\
+ << ::nitrokey::misc::hexdump((const uint8_t *) (&x), sizeof x, false));
+
+namespace nitrokey {
+ namespace proto {
+
+ template<CommandID cmd_id>
+ class Command : semantics::non_constructible {
+ public:
+ constexpr static CommandID command_id() { return cmd_id; }
+
+ template<typename T>
+ std::string dissect(const T &) {
+ return std::string("Payload dissection is unavailable");
+ }
+ };
+
+namespace stick20{
+ enum class PasswordKind : uint8_t {
+ User = 'P',
+ Admin = 'A',
+ AdminPrefixed
+ };
+
+ template<CommandID cmd_id, PasswordKind Tpassword_kind = PasswordKind::User, int password_length = 20>
+ class PasswordCommand : public Command<cmd_id> {
+ constexpr static CommandID _command_id() { return cmd_id; }
+ public:
+ struct CommandPayload {
+ uint8_t kind;
+ uint8_t password[password_length];
+
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss( kind );
+ print_to_ss_volatile(password);
+ return ss.str();
+ }
+ void set_kind_admin() {
+ kind = (uint8_t) 'A';
+ }
+ void set_kind_admin_prefixed() {
+ kind = (uint8_t) 'P';
+ }
+ void set_kind_user() {
+ kind = (uint8_t) 'P';
+ }
+
+ void set_defaults(){
+ set_kind(Tpassword_kind);
+ }
+
+ void set_kind(PasswordKind password_kind){
+ switch (password_kind){
+ case PasswordKind::Admin:
+ set_kind_admin();
+ break;
+ case PasswordKind::User:
+ set_kind_user();
+ break;
+ case PasswordKind::AdminPrefixed:
+ set_kind_admin_prefixed();
+ break;
+ }
+ };
+
+ } __packed;
+
+ //typedef Transaction<Command<cmd_id>::command_id(), struct CommandPayload, struct EmptyPayload>
+ // CommandTransaction;
+ using CommandTransaction = Transaction<cmd_id, CommandPayload, EmptyPayload>;
+ //using CommandTransaction = Transaction<_command_id(), CommandPayload, EmptyPayload>;
+
+ };
+ }
+ }
+}
+
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/command_id.h b/libnitrokey-3.3/libnitrokey/command_id.h
new file mode 100644
index 0000000..1092ea9
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/command_id.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef COMMAND_ID_H
+#define COMMAND_ID_H
+#include <stdint.h>
+
+namespace nitrokey {
+namespace proto {
+ namespace stick20 {
+ enum class device_status : uint8_t {
+ idle = 0,
+ ok,
+ busy,
+ wrong_password,
+ busy_progressbar,
+ password_matrix_ready,
+ no_user_password_unlock, // FIXME: translate on receive to command status error (fix in firmware?)
+ smartcard_error,
+ security_bit_active
+ };
+ const int CMD_START_VALUE = 0x20;
+ const int CMD_END_VALUE = 0x60;
+ }
+ namespace stick10 {
+ enum class command_status : uint8_t {
+ ok = 0,
+ wrong_CRC,
+ wrong_slot,
+ slot_not_programmed,
+ wrong_password = 4,
+ not_authorized,
+ timestamp_warning,
+ no_name_error,
+ not_supported,
+ unknown_command,
+ AES_dec_failed
+ };
+ enum class device_status : uint8_t {
+ ok = 0,
+ busy = 1,
+ error,
+ received_report,
+ };
+ }
+
+
+enum class CommandID : uint8_t {
+ GET_STATUS = 0x00,
+ WRITE_TO_SLOT = 0x01,
+ READ_SLOT_NAME = 0x02,
+ READ_SLOT = 0x03,
+ GET_CODE = 0x04,
+ WRITE_CONFIG = 0x05,
+ ERASE_SLOT = 0x06,
+ FIRST_AUTHENTICATE = 0x07,
+ AUTHORIZE = 0x08,
+ GET_PASSWORD_RETRY_COUNT = 0x09,
+ CLEAR_WARNING = 0x0A,
+ SET_TIME = 0x0B,
+ TEST_COUNTER = 0x0C,
+ TEST_TIME = 0x0D,
+ USER_AUTHENTICATE = 0x0E,
+ GET_USER_PASSWORD_RETRY_COUNT = 0x0F,
+ USER_AUTHORIZE = 0x10,
+ UNLOCK_USER_PASSWORD = 0x11,
+ LOCK_DEVICE = 0x12,
+ FACTORY_RESET = 0x13,
+ CHANGE_USER_PIN = 0x14,
+ CHANGE_ADMIN_PIN = 0x15,
+ WRITE_TO_SLOT_2 = 0x16,
+ SEND_OTP_DATA = 0x17,
+
+ ENABLE_CRYPTED_PARI = 0x20,
+ DISABLE_CRYPTED_PARI = 0x20 + 1,
+ ENABLE_HIDDEN_CRYPTED_PARI = 0x20 + 2,
+ DISABLE_HIDDEN_CRYPTED_PARI = 0x20 + 3,
+ ENABLE_FIRMWARE_UPDATE = 0x20 + 4, //enables update mode
+ EXPORT_FIRMWARE_TO_FILE = 0x20 + 5,
+ GENERATE_NEW_KEYS = 0x20 + 6,
+ FILL_SD_CARD_WITH_RANDOM_CHARS = 0x20 + 7,
+
+ WRITE_STATUS_DATA = 0x20 + 8, //@unused
+ ENABLE_READONLY_UNCRYPTED_LUN = 0x20 + 9,
+ ENABLE_READWRITE_UNCRYPTED_LUN = 0x20 + 10,
+
+ SEND_PASSWORD_MATRIX = 0x20 + 11, //@unused
+ SEND_PASSWORD_MATRIX_PINDATA = 0x20 + 12, //@unused
+ SEND_PASSWORD_MATRIX_SETUP = 0x20 + 13, //@unused
+
+ GET_DEVICE_STATUS = 0x20 + 14,
+ SEND_DEVICE_STATUS = 0x20 + 15,
+
+ SEND_HIDDEN_VOLUME_PASSWORD = 0x20 + 16, //@unused
+ SEND_HIDDEN_VOLUME_SETUP = 0x20 + 17,
+ SEND_PASSWORD = 0x20 + 18,
+ SEND_NEW_PASSWORD = 0x20 + 19,
+ CLEAR_NEW_SD_CARD_FOUND = 0x20 + 20,
+
+ SEND_STARTUP = 0x20 + 21,
+ SEND_CLEAR_STICK_KEYS_NOT_INITIATED = 0x20 + 22,
+ SEND_LOCK_STICK_HARDWARE = 0x20 + 23, //locks firmware upgrade
+
+ PRODUCTION_TEST = 0x20 + 24,
+ SEND_DEBUG_DATA = 0x20 + 25, //@unused
+
+ CHANGE_UPDATE_PIN = 0x20 + 26,
+
+ //added in v0.48.5
+ ENABLE_ADMIN_READONLY_UNCRYPTED_LUN = 0x20 + 28,
+ ENABLE_ADMIN_READWRITE_UNCRYPTED_LUN = 0x20 + 29,
+ ENABLE_ADMIN_READONLY_ENCRYPTED_LUN = 0x20 + 30,
+ ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN = 0x20 + 31,
+ CHECK_SMARTCARD_USAGE = 0x20 + 32,
+
+ GET_PW_SAFE_SLOT_STATUS = 0x60,
+ GET_PW_SAFE_SLOT_NAME = 0x61,
+ GET_PW_SAFE_SLOT_PASSWORD = 0x62,
+ GET_PW_SAFE_SLOT_LOGINNAME = 0x63,
+ SET_PW_SAFE_SLOT_DATA_1 = 0x64,
+ SET_PW_SAFE_SLOT_DATA_2 = 0x65,
+ PW_SAFE_ERASE_SLOT = 0x66,
+ PW_SAFE_ENABLE = 0x67,
+ PW_SAFE_INIT_KEY = 0x68, //@unused
+ PW_SAFE_SEND_DATA = 0x69, //@unused
+ SD_CARD_HIGH_WATERMARK = 0x70,
+ DETECT_SC_AES = 0x6a,
+ NEW_AES_KEY = 0x6b
+};
+
+const char *commandid_to_string(CommandID id);
+}
+}
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/cxx_semantics.h b/libnitrokey-3.3/libnitrokey/cxx_semantics.h
new file mode 100644
index 0000000..36ed142
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/cxx_semantics.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef CXX_SEMANTICS_H
+#define CXX_SEMANTICS_H
+
+#ifndef _MSC_VER
+#define __packed __attribute__((__packed__))
+#else
+#define __packed
+#endif
+
+#ifdef _MSC_VER
+#define strdup _strdup
+#endif
+
+/*
+ * There's no need to include Boost for a simple subset this project needs.
+ */
+namespace semantics {
+class non_constructible {
+ non_constructible() {}
+};
+}
+
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/device.h b/libnitrokey-3.3/libnitrokey/device.h
new file mode 100644
index 0000000..f6d2380
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/device.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef DEVICE_H
+#define DEVICE_H
+#include <chrono>
+#include "hidapi/hidapi.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#define HID_REPORT_SIZE 65
+
+#include <atomic>
+
+namespace nitrokey {
+namespace device {
+ using namespace std::chrono_literals;
+ using std::chrono::milliseconds;
+
+ struct EnumClassHash
+ {
+ template <typename T>
+ std::size_t operator()(T t) const
+ {
+ return static_cast<std::size_t>(t);
+ }
+ };
+
+enum class DeviceModel{
+ PRO,
+ STORAGE
+};
+
+#include <atomic>
+
+class Device {
+
+public:
+
+ struct ErrorCounters{
+ using cnt = std::atomic_int;
+ cnt wrong_CRC;
+ cnt CRC_other_than_awaited;
+ cnt busy;
+ cnt total_retries;
+ cnt sending_error;
+ cnt receiving_error;
+ cnt total_comm_runs;
+ cnt successful_storage_commands;
+ cnt command_successful_recv;
+ cnt recv_executed;
+ cnt sends_executed;
+ cnt busy_progressbar;
+ cnt command_result_not_equal_0_recv;
+ cnt communication_successful;
+ cnt low_level_reconnect;
+ std::string get_as_string();
+
+ } m_counters = {};
+
+
+ Device(const uint16_t vid, const uint16_t pid, const DeviceModel model,
+ const milliseconds send_receive_delay, const int retry_receiving_count,
+ const milliseconds retry_timeout);
+
+ virtual ~Device();
+
+ // lack of device is not actually an error,
+ // so it doesn't throw
+ virtual bool connect();
+ virtual bool disconnect();
+
+ /*
+ * Sends packet of HID_REPORT_SIZE.
+ */
+ virtual int send(const void *packet);
+
+ /*
+ * Gets packet of HID_REPORT_SIZE.
+ * Can sleep. See below.
+ */
+ virtual int recv(void *packet);
+
+ /***
+ * Returns true if some device is visible by OS with given VID and PID
+ * whether the device is connected through HID API or not.
+ * @return true if visible by OS
+ */
+ bool could_be_enumerated();
+ std::vector<std::string> enumerate();
+
+
+ void show_stats();
+// ErrorCounters get_stats(){ return m_counters; }
+ int get_retry_receiving_count() const { return m_retry_receiving_count; };
+ int get_retry_sending_count() const { return m_retry_sending_count; };
+ std::chrono::milliseconds get_retry_timeout() const { return m_retry_timeout; };
+ std::chrono::milliseconds get_send_receive_delay() const {return m_send_receive_delay;}
+
+ int get_last_command_status() {int a = std::atomic_exchange(&last_command_status, static_cast<uint8_t>(0)); return a;};
+ void set_last_command_status(uint8_t _err) { last_command_status = _err;} ;
+ bool last_command_sucessfull() const {return last_command_status == 0;};
+ DeviceModel get_device_model() const {return m_model;}
+ void set_receiving_delay(std::chrono::milliseconds delay);
+ void set_retry_delay(std::chrono::milliseconds delay);
+ static void set_default_device_speed(int delay);
+ void setDefaultDelay();
+ void set_path(const std::string path);
+
+
+ private:
+ std::atomic<uint8_t> last_command_status;
+ void _reconnect();
+ bool _connect();
+ bool _disconnect();
+
+protected:
+ const uint16_t m_vid;
+ const uint16_t m_pid;
+ const DeviceModel m_model;
+
+ /*
+ * While the project uses Signal11 portable HIDAPI
+ * library, there's no way of doing it asynchronously,
+ * hence polling.
+ */
+ const int m_retry_sending_count;
+ const int m_retry_receiving_count;
+ std::chrono::milliseconds m_retry_timeout;
+ std::chrono::milliseconds m_send_receive_delay;
+ std::atomic<hid_device *>mp_devhandle;
+ std::string m_path;
+
+ static std::atomic_int instances_count;
+ static std::chrono::milliseconds default_delay ;
+};
+
+class Stick10 : public Device {
+ public:
+ Stick10();
+
+};
+
+class Stick20 : public Device {
+ public:
+ Stick20();
+};
+}
+}
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/device_proto.h b/libnitrokey-3.3/libnitrokey/device_proto.h
new file mode 100644
index 0000000..45a6c16
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/device_proto.h
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef DEVICE_PROTO_H
+#define DEVICE_PROTO_H
+
+#include <utility>
+#include <thread>
+#include <type_traits>
+#include <stdexcept>
+#include <string>
+// a local version for compatibility with Windows
+#include <stdint.h>
+#include "cxx_semantics.h"
+#include "device.h"
+#include "misc.h"
+#include "log.h"
+#include "command_id.h"
+#include "dissect.h"
+#include "CommandFailedException.h"
+#include "LongOperationInProgressException.h"
+
+#define STICK20_UPDATE_MODE_VID 0x03EB
+#define STICK20_UPDATE_MODE_PID 0x2FF1
+
+#define PAYLOAD_SIZE 53
+#define PWS_SLOT_COUNT 16
+#define PWS_SLOTNAME_LENGTH 11
+#define PWS_PASSWORD_LENGTH 20
+#define PWS_LOGINNAME_LENGTH 32
+
+#define PWS_SEND_PASSWORD 0
+#define PWS_SEND_LOGINNAME 1
+#define PWS_SEND_TAB 2
+#define PWS_SEND_CR 3
+
+#include <mutex>
+#include "DeviceCommunicationExceptions.h"
+#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
+
+namespace nitrokey {
+ namespace proto {
+ extern std::mutex send_receive_mtx;
+
+
+/*
+ * POD types for HID proto commands
+ * Instances are meant to be __packed.
+ *
+ * TODO (future) support for Big Endian
+ */
+#pragma pack (push,1)
+/*
+ * Every packet is a USB HID report (check USB spec)
+ */
+ template<CommandID cmd_id, typename Payload>
+ struct HIDReport {
+ uint8_t _zero;
+ CommandID command_id; // uint8_t
+ union {
+ uint8_t _padding[HID_REPORT_SIZE - 6];
+ Payload payload;
+ } __packed;
+ uint32_t crc;
+
+ // POD types can't have non-default constructors
+ // used in Transaction<>::run()
+ void initialize() {
+ bzero(this, sizeof *this);
+ command_id = cmd_id;
+ }
+
+ uint32_t calculate_CRC() const {
+ // w/o leading zero, a part of each HID packet
+ // w/o 4-byte crc
+ return misc::stm_crc32((const uint8_t *) (this) + 1,
+ (size_t) (HID_REPORT_SIZE - 5));
+ }
+
+ void update_CRC() { crc = calculate_CRC(); }
+
+ bool isCRCcorrect() const { return crc == calculate_CRC(); }
+
+ bool isValid() const {
+ return true;
+ // return !_zero && payload.isValid() && isCRCcorrect();
+ }
+
+ operator std::string() const {
+ // Packet type is known upfront in normal operation.
+ // Can't be used to dissect random packets.
+ return QueryDissector<cmd_id, decltype(*this)>::dissect(*this);
+ }
+ } __packed;
+
+/*
+ * Response payload (the parametrized type inside struct HIDReport)
+ *
+ * command_id member in incoming HIDReport structure carries the command
+ * type last used.
+ */
+ namespace DeviceResponseConstants{
+ //magic numbers from firmware
+ static constexpr auto storage_status_absolute_address = 21;
+ static constexpr auto storage_data_absolute_address = storage_status_absolute_address + 5;
+ static constexpr auto header_size = 8; //from _zero to last_command_status inclusive
+ static constexpr auto footer_size = 4; //crc
+ static constexpr auto wrapping_size = header_size + footer_size;
+ }
+
+ template<CommandID cmd_id, typename ResponsePayload>
+ struct DeviceResponse {
+ static constexpr auto storage_status_padding_size =
+ DeviceResponseConstants::storage_status_absolute_address - DeviceResponseConstants::header_size;
+
+ uint8_t _zero;
+ uint8_t device_status;
+ uint8_t command_id; // originally last_command_type
+ uint32_t last_command_crc;
+ uint8_t last_command_status;
+
+ union {
+ uint8_t _padding[HID_REPORT_SIZE - DeviceResponseConstants::wrapping_size];
+ ResponsePayload payload;
+ struct {
+ uint8_t _storage_status_padding[storage_status_padding_size];
+ uint8_t command_counter;
+ uint8_t command_id;
+ uint8_t device_status; //@see stick20::device_status
+ uint8_t progress_bar_value;
+ } __packed storage_status;
+ } __packed;
+
+ uint32_t crc;
+
+ void initialize() { bzero(this, sizeof *this); }
+
+ uint32_t calculate_CRC() const {
+ // w/o leading zero, a part of each HID packet
+ // w/o 4-byte crc
+ return misc::stm_crc32((const uint8_t *) (this) + 1,
+ (size_t) (HID_REPORT_SIZE - 5));
+ }
+
+ void update_CRC() { crc = calculate_CRC(); }
+ bool isCRCcorrect() const { return crc == calculate_CRC(); }
+ bool isValid() const {
+ // return !_zero && payload.isValid() && isCRCcorrect() &&
+ // command_id == (uint8_t)(cmd_id);
+ return crc != 0;
+ }
+
+ operator std::string() const {
+ return ResponseDissector<cmd_id, decltype(*this)>::dissect(*this);
+ }
+ } __packed;
+
+ struct EmptyPayload {
+ bool isValid() const { return true; }
+
+ std::string dissect() const { return std::string("Empty Payload."); }
+ } __packed;
+
+ template<typename command_packet, typename response_payload>
+ class ClearingProxy {
+ public:
+ ClearingProxy(command_packet &p) {
+ packet = p;
+ bzero(&p, sizeof(p));
+ }
+
+ ~ClearingProxy() {
+ bzero(&packet, sizeof(packet));
+ }
+
+ response_payload &data() {
+ return packet.payload;
+ }
+
+ command_packet packet;
+ };
+
+ template<CommandID cmd_id, typename command_payload, typename response_payload>
+ class Transaction : semantics::non_constructible {
+ public:
+ // Types declared in command class scope can't be reached from there.
+ typedef command_payload CommandPayload;
+ typedef response_payload ResponsePayload;
+
+
+ typedef struct HIDReport<cmd_id, CommandPayload> OutgoingPacket;
+ typedef struct DeviceResponse<cmd_id, ResponsePayload> ResponsePacket;
+#pragma pack (pop)
+
+ static_assert(std::is_pod<OutgoingPacket>::value,
+ "outgoingpacket must be a pod type");
+ static_assert(std::is_pod<ResponsePacket>::value,
+ "ResponsePacket must be a POD type");
+ static_assert(sizeof(OutgoingPacket) == HID_REPORT_SIZE,
+ "OutgoingPacket type is not the right size");
+ static_assert(sizeof(ResponsePacket) == HID_REPORT_SIZE,
+ "ResponsePacket type is not the right size");
+
+ static uint32_t getCRC(
+ const command_payload &payload) {
+ OutgoingPacket outp;
+ outp.initialize();
+ outp.payload = payload;
+ outp.update_CRC();
+ return outp.crc;
+ }
+
+ template<typename T>
+ static void clear_packet(T &st) {
+ bzero(&st, sizeof(st));
+ }
+
+ static ClearingProxy<ResponsePacket, response_payload> run(std::shared_ptr<device::Device> dev,
+ const command_payload &payload) {
+ using namespace ::nitrokey::device;
+ using namespace ::nitrokey::log;
+ using namespace std::chrono_literals;
+
+ std::lock_guard<std::mutex> guard(send_receive_mtx);
+
+ LOG(__FUNCTION__, Loglevel::DEBUG_L2);
+
+ if (dev == nullptr){
+ LOG(std::string("Throw: Device not initialized"), Loglevel::DEBUG_L1);
+ throw DeviceNotConnected("Device not initialized");
+ }
+ dev->m_counters.total_comm_runs++;
+
+ int status;
+ OutgoingPacket outp;
+ ResponsePacket resp;
+
+ // POD types can't have non-default constructors
+ outp.initialize();
+ resp.initialize();
+
+ outp.payload = payload;
+ outp.update_CRC();
+
+ LOG("-------------------", Loglevel::DEBUG);
+ LOG("Outgoing HID packet:", Loglevel::DEBUG);
+ LOG(static_cast<std::string>(outp), Loglevel::DEBUG);
+ LOG(std::string("=> ") + std::string(commandid_to_string(static_cast<CommandID>(outp.command_id))), Loglevel::DEBUG_L1);
+
+
+ if (!outp.isValid()) {
+ LOG(std::string("Throw: Invalid outgoing packet"), Loglevel::DEBUG_L1);
+ throw DeviceSendingFailure("Invalid outgoing packet");
+ }
+
+ bool successful_communication = false;
+ int receiving_retry_counter = 0;
+ int sending_retry_counter = dev->get_retry_sending_count();
+ while (sending_retry_counter-- > 0) {
+ dev->m_counters.sends_executed++;
+ status = dev->send(&outp);
+ if (status <= 0){
+ //FIXME early disconnection not yet working properly
+// LOG("Encountered communication error, disconnecting device", Loglevel::DEBUG_L2);
+// dev->disconnect();
+ dev->m_counters.sending_error++;
+ LOG(std::string("Throw: Device error while sending command "), Loglevel::DEBUG_L1);
+ throw DeviceSendingFailure(
+ std::string("Device error while sending command ") +
+ std::to_string(status));
+ }
+
+ std::this_thread::sleep_for(dev->get_send_receive_delay());
+
+ // FIXME make checks done in device:recv here
+ receiving_retry_counter = dev->get_retry_receiving_count();
+ int busy_counter = 0;
+ auto retry_timeout = dev->get_retry_timeout();
+ while (receiving_retry_counter-- > 0) {
+ dev->m_counters.recv_executed++;
+ status = dev->recv(&resp);
+
+ if (dev->get_device_model() == DeviceModel::STORAGE &&
+ resp.command_id >= stick20::CMD_START_VALUE &&
+ resp.command_id < stick20::CMD_END_VALUE ) {
+ LOG(std::string("Detected storage device cmd, status: ") +
+ std::to_string(resp.storage_status.device_status), Loglevel::DEBUG_L2);
+
+ resp.last_command_status = static_cast<uint8_t>(stick10::command_status::ok);
+ switch (static_cast<stick20::device_status>(resp.storage_status.device_status)) {
+ case stick20::device_status::idle :
+ case stick20::device_status::ok:
+ resp.device_status = static_cast<uint8_t>(stick10::device_status::ok);
+ break;
+ case stick20::device_status::busy:
+ case stick20::device_status::busy_progressbar: //TODO this will be modified later for getting progressbar status
+ resp.device_status = static_cast<uint8_t>(stick10::device_status::busy);
+ break;
+ case stick20::device_status::wrong_password:
+ resp.last_command_status = static_cast<uint8_t>(stick10::command_status::wrong_password);
+ resp.device_status = static_cast<uint8_t>(stick10::device_status::ok);
+ break;
+ case stick20::device_status::no_user_password_unlock:
+ resp.last_command_status = static_cast<uint8_t>(stick10::command_status::AES_dec_failed);
+ resp.device_status = static_cast<uint8_t>(stick10::device_status::ok);
+ break;
+ default:
+ LOG(std::string("Unknown storage device status, cannot translate: ") +
+ std::to_string(resp.storage_status.device_status), Loglevel::DEBUG);
+ resp.device_status = resp.storage_status.device_status;
+ break;
+ };
+ }
+
+ //Some of the commands return wrong CRC, for now skip checking it (TODO list and report)
+ //if (resp.device_status == 0 && resp.last_command_crc == outp.crc && resp.isCRCcorrect()) break;
+ auto CRC_equal_awaited = true; // resp.last_command_crc == outp.crc;
+ if (resp.device_status == static_cast<uint8_t>(stick10::device_status::ok) &&
+ CRC_equal_awaited && resp.isValid()){
+ successful_communication = true;
+ break;
+ }
+ if (resp.device_status == static_cast<uint8_t>(stick10::device_status::busy)) {
+ dev->m_counters.busy++;
+
+ if (busy_counter++<10) {
+ receiving_retry_counter++;
+ LOG("Status busy, not decreasing receiving_retry_counter counter: " +
+ std::to_string(receiving_retry_counter), Loglevel::DEBUG_L2);
+ } else {
+ retry_timeout *= 2;
+ retry_timeout = std::min(retry_timeout, 300ms);
+ busy_counter = 0;
+ LOG("Status busy, decreasing receiving_retry_counter counter: " +
+ std::to_string(receiving_retry_counter) + ", current delay:"
+ + std::to_string(retry_timeout.count()), Loglevel::DEBUG);
+ LOG(std::string("Busy retry: status ")
+ + std::to_string(resp.storage_status.device_status)
+ + ", "
+ + std::to_string(retry_timeout.count())
+ + "ms, counter "
+ + std::to_string(receiving_retry_counter)
+ + ", progress: "
+ + std::to_string(resp.storage_status.progress_bar_value)
+ , Loglevel::DEBUG_L1);
+ }
+ }
+ if (resp.device_status == static_cast<uint8_t>(stick10::device_status::busy) &&
+ static_cast<stick20::device_status>(resp.storage_status.device_status)
+ == stick20::device_status::busy_progressbar){
+ successful_communication = true;
+ break;
+ }
+ LOG(std::string("Retry status - dev status, awaited cmd crc, correct packet CRC: ")
+ + std::to_string(resp.device_status) +
+ " " + std::to_string(CRC_equal_awaited) +
+ " " + std::to_string(resp.isCRCcorrect()), Loglevel::DEBUG_L2);
+
+ if (!resp.isCRCcorrect()) dev->m_counters.wrong_CRC++;
+ if (!CRC_equal_awaited) dev->m_counters.CRC_other_than_awaited++;
+
+
+ LOG(
+ "Device is not ready or received packet's last CRC is not equal to sent CRC packet, retrying...",
+ Loglevel::DEBUG_L2);
+ LOG("Invalid incoming HID packet:", Loglevel::DEBUG_L2);
+ LOG(static_cast<std::string>(resp), Loglevel::DEBUG_L2);
+ dev->m_counters.total_retries++;
+ LOG(".", Loglevel::DEBUG_L1);
+ std::this_thread::sleep_for(retry_timeout);
+ continue;
+ }
+ if (successful_communication) break;
+ LOG(std::string("Resending (outer loop) "), Loglevel::DEBUG_L2);
+ LOG(std::string("sending_retry_counter count: ") + std::to_string(sending_retry_counter),
+ Loglevel::DEBUG);
+ }
+
+ if(resp.last_command_crc != outp.crc){
+ LOG(std::string("Accepting response with CRC other than expected ")
+ + "Command ID: " + std::to_string(resp.command_id) + " " +
+ commandid_to_string(static_cast<CommandID>(resp.command_id)) + " "
+ + "Reported by response and expected: " + std::to_string(resp.last_command_crc) + "!=" + std::to_string(outp.crc),
+ Loglevel::WARNING
+ );
+ }
+
+ dev->set_last_command_status(resp.last_command_status); // FIXME should be handled on device.recv
+
+ clear_packet(outp);
+
+
+ if (status <= 0) {
+ dev->m_counters.receiving_error++;
+ LOG(std::string("Throw: Device error while executing command "), Loglevel::DEBUG_L1);
+ throw DeviceReceivingFailure( //FIXME replace with CriticalErrorException
+ std::string("Device error while executing command ") +
+ std::to_string(status));
+ }
+
+ LOG(std::string("<= ") +
+ std::string(
+ commandid_to_string(static_cast<CommandID>(resp.command_id))
+ + std::string(" ")
+ + std::to_string(resp.device_status)
+ + std::string(" ")
+ + std::to_string(resp.storage_status.device_status)
+// + std::to_string( status_translate_command(resp.storage_status.device_status))
+ ), Loglevel::DEBUG_L1);
+
+ LOG("Incoming HID packet:", Loglevel::DEBUG);
+ LOG(static_cast<std::string>(resp), Loglevel::DEBUG);
+ if (dev->get_retry_receiving_count() - receiving_retry_counter > 2) {
+ LOG(std::string("Packet received with receiving_retry_counter count: ") +
+ std::to_string(receiving_retry_counter),
+ Loglevel::DEBUG_L1);
+ }
+
+ if (resp.device_status == static_cast<uint8_t>(stick10::device_status::busy) &&
+ static_cast<stick20::device_status>(resp.storage_status.device_status)
+ == stick20::device_status::busy_progressbar){
+ dev->m_counters.busy_progressbar++;
+ LOG(std::string("Throw: Long operation in progress exception"), Loglevel::DEBUG_L1);
+ throw LongOperationInProgressException(
+ resp.command_id, resp.device_status, resp.storage_status.progress_bar_value);
+ }
+
+ if (!resp.isValid()) {
+ LOG(std::string("Throw: Invalid incoming packet"), Loglevel::DEBUG_L1);
+ throw InvalidCRCReceived("Invalid incoming packet");
+ }
+ if (receiving_retry_counter <= 0){
+ LOG(std::string("Throw: \"Maximum receiving_retry_counter count reached for receiving response from the device!\""
+ + std::to_string(receiving_retry_counter)), Loglevel::DEBUG_L1);
+ throw DeviceReceivingFailure(
+ "Maximum receiving_retry_counter count reached for receiving response from the device!");
+ }
+ dev->m_counters.communication_successful++;
+
+ if (resp.last_command_status != static_cast<uint8_t>(stick10::command_status::ok)){
+ dev->m_counters.command_result_not_equal_0_recv++;
+ LOG(std::string("Throw: CommandFailedException ") + std::to_string(resp.last_command_status), Loglevel::DEBUG_L1);
+ throw CommandFailedException(resp.command_id, resp.last_command_status);
+ }
+
+ dev->m_counters.command_successful_recv++;
+
+ if (dev->get_device_model() == DeviceModel::STORAGE &&
+ resp.command_id >= stick20::CMD_START_VALUE &&
+ resp.command_id < stick20::CMD_END_VALUE ) {
+ dev->m_counters.successful_storage_commands++;
+ }
+
+ if (!resp.isCRCcorrect())
+ LOG(std::string("Accepting response from device with invalid CRC. ")
+ + "Command ID: " + std::to_string(resp.command_id) + " " +
+ commandid_to_string(static_cast<CommandID>(resp.command_id)) + " "
+ + "Reported and calculated: " + std::to_string(resp.crc) + "!=" + std::to_string(resp.calculate_CRC()),
+ Loglevel::WARNING
+ );
+
+ // See: DeviceResponse
+ return resp;
+ }
+
+ static ClearingProxy<ResponsePacket, response_payload> run(std::shared_ptr<device::Device> dev) {
+ command_payload empty_payload;
+ return run(dev, empty_payload);
+ }
+ };
+ }
+}
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/dissect.h b/libnitrokey-3.3/libnitrokey/dissect.h
new file mode 100644
index 0000000..690b5b7
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/dissect.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+/*
+ * Protocol packet dissection
+ */
+#ifndef DISSECT_H
+#define DISSECT_H
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include "misc.h"
+#include "cxx_semantics.h"
+#include "command_id.h"
+#include "device_proto.h"
+
+namespace nitrokey {
+namespace proto {
+
+template <CommandID id, class HIDPacket>
+class QueryDissector : semantics::non_constructible {
+ public:
+ static std::string dissect(const HIDPacket &pod) {
+ std::stringstream out;
+
+#ifdef LOG_VOLATILE_DATA
+ out << "Raw HID packet:" << std::endl;
+ out << ::nitrokey::misc::hexdump((const uint8_t *)(&pod), sizeof pod);
+#endif
+
+ out << "Contents:" << std::endl;
+ out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id))
+ << std::endl;
+ out << "CRC:\t"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << pod.crc << std::endl;
+
+ out << "Payload:" << std::endl;
+ out << pod.payload.dissect();
+ return out.str();
+ }
+};
+
+
+
+
+template <CommandID id, class HIDPacket>
+class ResponseDissector : semantics::non_constructible {
+ public:
+ static std::string status_translate_device(int status){
+ auto enum_status = static_cast<proto::stick10::device_status>(status);
+ switch (enum_status){
+ case stick10::device_status::ok: return "OK";
+ case stick10::device_status::busy: return "BUSY";
+ case stick10::device_status::error: return "ERROR";
+ case stick10::device_status::received_report: return "RECEIVED_REPORT";
+ }
+ return std::string("UNKNOWN: ") + std::to_string(status);
+ }
+
+ static std::string to_upper(std::string str){
+ for (auto & c: str) c = toupper(c);
+ return str;
+ }
+ static std::string status_translate_command(int status){
+ auto enum_status = static_cast<proto::stick10::command_status >(status);
+ switch (enum_status) {
+#define p(X) case X: return to_upper(std::string(#X));
+ p(stick10::command_status::ok)
+ p(stick10::command_status::wrong_CRC)
+ p(stick10::command_status::wrong_slot)
+ p(stick10::command_status::slot_not_programmed)
+ p(stick10::command_status::wrong_password)
+ p(stick10::command_status::not_authorized)
+ p(stick10::command_status::timestamp_warning)
+ p(stick10::command_status::no_name_error)
+ p(stick10::command_status::not_supported)
+ p(stick10::command_status::unknown_command)
+ p(stick10::command_status::AES_dec_failed)
+#undef p
+ }
+ return std::string("UNKNOWN: ") + std::to_string(status);
+ }
+
+ static std::string dissect(const HIDPacket &pod) {
+ std::stringstream out;
+
+ // FIXME use values from firmware (possibly generate separate
+ // header automatically)
+
+#ifdef LOG_VOLATILE_DATA
+ out << "Raw HID packet:" << std::endl;
+ out << ::nitrokey::misc::hexdump((const uint8_t *)(&pod), sizeof pod);
+#endif
+
+ out << "Device status:\t" << pod.device_status + 0 << " "
+ << status_translate_device(pod.device_status) << std::endl;
+ out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) << " hex: " << std::hex << (int)pod.command_id
+ << std::endl;
+ out << "Last command CRC:\t"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << pod.last_command_crc << std::endl;
+ out << "Last command status:\t" << pod.last_command_status + 0 << " "
+ << status_translate_command(pod.last_command_status) << std::endl;
+ out << "CRC:\t"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << pod.crc << std::endl;
+ if((int)pod.command_id == pod.storage_status.command_id){
+ out << "Storage stick status (where applicable):" << std::endl;
+#define d(x) out << " "#x": \t"<< std::hex << std::setw(2) \
+ << std::setfill('0')<< static_cast<int>(x) << std::endl;
+ d(pod.storage_status.command_counter);
+ d(pod.storage_status.command_id);
+ d(pod.storage_status.device_status);
+ d(pod.storage_status.progress_bar_value);
+#undef d
+ }
+
+ out << "Payload:" << std::endl;
+ out << pod.payload.dissect();
+ return out.str();
+ }
+};
+}
+}
+
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/hidapi/hidapi.h b/libnitrokey-3.3/libnitrokey/hidapi/hidapi.h
new file mode 100644
index 0000000..e5bc2dc
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/hidapi/hidapi.h
@@ -0,0 +1,391 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+/** @file
+ * @defgroup API hidapi API
+ */
+
+#ifndef HIDAPI_H__
+#define HIDAPI_H__
+
+#include <wchar.h>
+
+#ifdef _WIN32
+ #define HID_API_EXPORT __declspec(dllexport)
+ #define HID_API_CALL
+#else
+ #define HID_API_EXPORT /**< API export macro */
+ #define HID_API_CALL /**< API call macro */
+#endif
+
+#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ struct hid_device_;
+ typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
+
+ /** hidapi info structure */
+ struct hid_device_info {
+ /** Platform-specific device path */
+ char *path;
+ /** Device Vendor ID */
+ unsigned short vendor_id;
+ /** Device Product ID */
+ unsigned short product_id;
+ /** Serial Number */
+ wchar_t *serial_number;
+ /** Device Release Number in binary-coded decimal,
+ also known as Device Version Number */
+ unsigned short release_number;
+ /** Manufacturer String */
+ wchar_t *manufacturer_string;
+ /** Product string */
+ wchar_t *product_string;
+ /** Usage Page for this Device/Interface
+ (Windows/Mac only). */
+ unsigned short usage_page;
+ /** Usage for this Device/Interface
+ (Windows/Mac only).*/
+ unsigned short usage;
+ /** The USB interface which this logical device
+ represents. Valid on both Linux implementations
+ in all cases, and valid on the Windows implementation
+ only if the device contains more than one interface. */
+ int interface_number;
+
+ /** Pointer to the next device */
+ struct hid_device_info *next;
+ };
+
+
+ /** @brief Initialize the HIDAPI library.
+
+ This function initializes the HIDAPI library. Calling it is not
+ strictly necessary, as it will be called automatically by
+ hid_enumerate() and any of the hid_open_*() functions if it is
+ needed. This function should be called at the beginning of
+ execution however, if there is a chance of HIDAPI handles
+ being opened by different threads simultaneously.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_init(void);
+
+ /** @brief Finalize the HIDAPI library.
+
+ This function frees all of the static data associated with
+ HIDAPI. It should be called at the end of execution to avoid
+ memory leaks.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_exit(void);
+
+ /** @brief Enumerate the HID Devices.
+
+ This function returns a linked list of all the HID devices
+ attached to the system which match vendor_id and product_id.
+ If @p vendor_id is set to 0 then any vendor matches.
+ If @p product_id is set to 0 then any product matches.
+ If @p vendor_id and @p product_id are both set to 0, then
+ all HID devices will be returned.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the types of device
+ to open.
+ @param product_id The Product ID (PID) of the types of
+ device to open.
+
+ @returns
+ This function returns a pointer to a linked list of type
+ struct #hid_device, containing information about the HID devices
+ attached to the system, or NULL in the case of failure. Free
+ this linked list by calling hid_free_enumeration().
+ */
+ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
+
+ /** @brief Free an enumeration Linked List
+
+ This function frees a linked list created by hid_enumerate().
+
+ @ingroup API
+ @param devs Pointer to a list of struct_device returned from
+ hid_enumerate().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
+
+ /** @brief Open a HID device using a Vendor ID (VID), Product ID
+ (PID) and optionally a serial number.
+
+ If @p serial_number is NULL, the first device with the
+ specified VID and PID is opened.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the device to open.
+ @param product_id The Product ID (PID) of the device to open.
+ @param serial_number The Serial Number of the device to open
+ (Optionally NULL).
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
+
+ /** @brief Open a HID device by its path name.
+
+ The path name be determined by calling hid_enumerate(), or a
+ platform-specific path name can be used (eg: /dev/hidraw0 on
+ Linux).
+
+ @ingroup API
+ @param path The path name of the device to open
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
+
+ /** @brief Write an Output report to a HID device.
+
+ The first byte of @p data[] must contain the Report ID. For
+ devices which only support a single report, this must be set
+ to 0x0. The remaining bytes contain the report data. Since
+ the Report ID is mandatory, calls to hid_write() will always
+ contain one more byte than the report contains. For example,
+ if a hid report is 16 bytes long, 17 bytes must be passed to
+ hid_write(), the Report ID (or 0x0, for devices with a
+ single report), followed by the report data (16 bytes). In
+ this example, the length passed in would be 17.
+
+ hid_write() will send the data on the first OUT endpoint, if
+ one exists. If it does not, it will send the data through
+ the Control Endpoint (Endpoint 0).
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Read an Input report from a HID device with timeout.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+ @param milliseconds timeout in milliseconds or -1 for blocking wait.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read within
+ the timeout period, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
+
+ /** @brief Read an Input report from a HID device.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read and
+ the handle is in non-blocking mode, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Set the device handle to be non-blocking.
+
+ In non-blocking mode calls to hid_read() will return
+ immediately with a value of 0 if there is no data to be
+ read. In blocking mode, hid_read() will wait (block) until
+ there is data to read before returning.
+
+ Nonblocking can be turned on and off at any time.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param nonblock enable or not the nonblocking reads
+ - 1 to enable nonblocking
+ - 0 to disable nonblocking.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
+
+ /** @brief Send a Feature report to the device.
+
+ Feature reports are sent over the Control endpoint as a
+ Set_Report transfer. The first byte of @p data[] must
+ contain the Report ID. For devices which only support a
+ single report, this must be set to 0x0. The remaining bytes
+ contain the report data. Since the Report ID is mandatory,
+ calls to hid_send_feature_report() will always contain one
+ more byte than the report contains. For example, if a hid
+ report is 16 bytes long, 17 bytes must be passed to
+ hid_send_feature_report(): the Report ID (or 0x0, for
+ devices which do not use numbered reports), followed by the
+ report data (16 bytes). In this example, the length passed
+ in would be 17.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send, including
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Get a feature report from a HID device.
+
+ Set the first byte of @p data[] to the Report ID of the
+ report to be read. Make sure to allow space for this
+ extra byte in @p data[]. Upon return, the first byte will
+ still contain the Report ID, and the report data will
+ start in data[1].
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into, including
+ the Report ID. Set the first byte of @p data[] to the
+ Report ID of the report to be read, or set it to zero
+ if your device does not use numbered reports.
+ @param length The number of bytes to read, including an
+ extra byte for the report ID. The buffer can be longer
+ than the actual report.
+
+ @returns
+ This function returns the number of bytes read plus
+ one for the report ID (which is still in the first
+ byte), or -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Close a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
+
+ /** @brief Get The Manufacturer String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Product String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Serial Number String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string from a HID device, based on its string index.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string_index The index of the string to get.
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string describing the last error which occurred.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+
+ @returns
+ This function returns a string containing the last error
+ which occurred or NULL if none has occurred.
+ */
+ HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libnitrokey-3.3/libnitrokey/log.h b/libnitrokey-3.3/libnitrokey/log.h
new file mode 100644
index 0000000..2a64bef
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/log.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef LOG_H
+#define LOG_H
+
+#include <string>
+#include <functional>
+
+namespace nitrokey {
+ namespace log {
+
+//for MSVC
+#ifdef ERROR
+#undef ERROR
+#endif
+
+
+ enum class Loglevel : int {
+ ERROR,
+ WARNING,
+ INFO,
+ DEBUG_L1,
+ DEBUG,
+ DEBUG_L2
+ };
+
+ class LogHandler {
+ public:
+ virtual void print(const std::string &, Loglevel lvl) = 0;
+ protected:
+ std::string loglevel_to_str(Loglevel);
+ std::string format_message_to_string(const std::string &str, const Loglevel &lvl);
+
+ };
+
+ class StdlogHandler : public LogHandler {
+ public:
+ virtual void print(const std::string &, Loglevel lvl);
+ };
+
+ class FunctionalLogHandler : public LogHandler {
+ using log_function_type = std::function<void(std::string)>;
+ log_function_type log_function;
+ public:
+ FunctionalLogHandler(log_function_type _log_function);
+ virtual void print(const std::string &, Loglevel lvl);
+
+ };
+
+ extern StdlogHandler stdlog_handler;
+
+ class Log {
+ public:
+ Log() : mp_loghandler(&stdlog_handler), m_loglevel(Loglevel::WARNING) {}
+
+ static Log &instance() {
+ if (mp_instance == nullptr) mp_instance = new Log;
+ return *mp_instance;
+ }
+
+ void operator()(const std::string &, Loglevel);
+ void set_loglevel(Loglevel lvl) { m_loglevel = lvl; }
+ void set_handler(LogHandler *handler) { mp_loghandler = handler; }
+
+ private:
+ LogHandler *mp_loghandler;
+ Loglevel m_loglevel;
+ static std::string prefix;
+ public:
+ static void setPrefix(std::string prefix = std::string());
+
+ private:
+
+ static Log *mp_instance;
+ };
+ }
+}
+
+
+#ifdef NO_LOG
+#define LOG(string, level) while(false){}
+#define LOGD(string) while(false){}
+#else
+#define LOG(string, level) nitrokey::log::Log::instance()((string), (level))
+#define LOGD1(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L1))
+#define LOGD(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L2))
+#endif
+
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/misc.h b/libnitrokey-3.3/libnitrokey/misc.h
new file mode 100644
index 0000000..88254dd
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/misc.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+
+#ifndef MISC_H
+#define MISC_H
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <string.h>
+#include "log.h"
+#include "LibraryException.h"
+#include <sstream>
+#include <iomanip>
+
+
+namespace nitrokey {
+namespace misc {
+
+ template<typename T>
+ std::string toHex(T value){
+ using namespace std;
+ std::ostringstream oss;
+ oss << std::hex << std::setw(sizeof(value)*2) << std::setfill('0') << value;
+ return oss.str();
+ }
+
+ /**
+ * Copies string from pointer to fixed size C-style array. Src needs to be a valid C-string - eg. ended with '\0'.
+ * Throws when source is bigger than destination.
+ * @tparam T type of destination array
+ * @param dest fixed size destination array
+ * @param src pointer to source c-style valid string
+ */
+ template <typename T>
+ void strcpyT(T& dest, const char* src){
+
+ if (src == nullptr)
+// throw EmptySourceStringException(slot_number);
+ return;
+ const size_t s_dest = sizeof dest;
+ LOG(std::string("strcpyT sizes dest src ")
+ +std::to_string(s_dest)+ " "
+ +std::to_string(strlen(src))+ " "
+ ,nitrokey::log::Loglevel::DEBUG_L2);
+ if (strlen(src) > s_dest){
+ throw TooLongStringException(strlen(src), s_dest, src);
+ }
+ strncpy((char*) &dest, src, s_dest);
+ }
+
+#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
+ template <typename T>
+typename T::CommandPayload get_payload(){
+ //Create, initialize and return by value command payload
+ typename T::CommandPayload st;
+ bzero(&st, sizeof(st));
+ return st;
+}
+
+ template<typename CMDTYPE, typename Tdev>
+ void execute_password_command(Tdev &stick, const char *password) {
+ auto p = get_payload<CMDTYPE>();
+ p.set_defaults();
+ strcpyT(p.password, password);
+ CMDTYPE::CommandTransaction::run(stick, p);
+ }
+
+ std::string hexdump(const uint8_t *p, size_t size, bool print_header=true, bool print_ascii=true,
+ bool print_empty=true);
+ uint32_t stm_crc32(const uint8_t *data, size_t size);
+ std::vector<uint8_t> hex_string_to_byte(const char* hexString);
+}
+}
+
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/stick10_commands.h b/libnitrokey-3.3/libnitrokey/stick10_commands.h
new file mode 100644
index 0000000..f2ffba2
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/stick10_commands.h
@@ -0,0 +1,889 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef STICK10_COMMANDS_H
+#define STICK10_COMMANDS_H
+
+#include <bitset>
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <stdint.h>
+#include "device_proto.h"
+#include "command.h"
+
+#pragma pack (push,1)
+
+namespace nitrokey {
+namespace proto {
+
+
+
+/*
+ * Stick10 protocol definition
+ */
+namespace stick10 {
+class GetSlotName : public Command<CommandID::READ_SLOT_NAME> {
+ public:
+ // reachable as a typedef in Transaction
+ struct CommandPayload {
+ uint8_t slot_number;
+
+ bool isValid() const { return slot_number<0x10+3; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_name[15];
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(slot_name);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload,
+ struct ResponsePayload> CommandTransaction;
+};
+
+class EraseSlot : Command<CommandID::ERASE_SLOT> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class SetTime : Command<CommandID::SET_TIME> {
+ public:
+ struct CommandPayload {
+ uint8_t reset; // 0 - get time, 1 - set time
+ uint64_t time; // posix time
+
+ bool isValid() const { return reset && reset != 1; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "reset:\t" << (int)(reset) << std::endl;
+ ss << "time:\t" << (time) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+
+class WriteToHOTPSlot : Command<CommandID::WRITE_TO_SLOT> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint8_t slot_name[15];
+ uint8_t slot_secret[20];
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ union{
+ uint8_t slot_token_id[13]; /** OATH Token Identifier */
+ struct{ /** @see https://openauthentication.org/token-specs/ */
+ uint8_t omp[2];
+ uint8_t tt[2];
+ uint8_t mui[8];
+ uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
+ } slot_token_fields;
+ };
+ union{
+ uint64_t slot_counter;
+ uint8_t slot_counter_s[8];
+ } __packed;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ print_to_ss_volatile(slot_name);
+ print_to_ss_volatile(slot_secret);
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+
+ ss << "slot_token_id:\t";
+ for (auto i : slot_token_id)
+ ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
+ ss << std::endl;
+ ss << "slot_counter:\t[" << (int)slot_counter << "]\t"
+ << ::nitrokey::misc::hexdump((const uint8_t *)(&slot_counter), sizeof slot_counter, false);
+
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class WriteToTOTPSlot : Command<CommandID::WRITE_TO_SLOT> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint8_t slot_name[15];
+ uint8_t slot_secret[20];
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ union{
+ uint8_t slot_token_id[13]; /** OATH Token Identifier */
+ struct{ /** @see https://openauthentication.org/token-specs/ */
+ uint8_t omp[2];
+ uint8_t tt[2];
+ uint8_t mui[8];
+ uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
+ } slot_token_fields;
+ };
+ uint16_t slot_interval;
+
+ bool isValid() const { return !(slot_number & 0xF0); } //TODO check
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ print_to_ss_volatile(slot_name);
+ print_to_ss_volatile(slot_secret);
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "slot_token_id:\t";
+ for (auto i : slot_token_id)
+ ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
+ ss << std::endl;
+ ss << "slot_interval:\t" << (int)slot_interval << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class GetTOTP : Command<CommandID::GET_CODE> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint64_t challenge;
+ uint64_t last_totp_time;
+ uint8_t last_interval;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ ss << "challenge:\t" << (challenge) << std::endl;
+ ss << "last_totp_time:\t" << (last_totp_time) << std::endl;
+ ss << "last_interval:\t" << (int)(last_interval) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ union {
+ uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
+ struct {
+ uint32_t code;
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ } __packed ;
+ } __packed ;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "code:\t" << (code) << std::endl;
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
+ CommandTransaction;
+};
+
+class GetHOTP : Command<CommandID::GET_CODE> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+
+ bool isValid() const { return (slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ union {
+ uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
+ struct {
+ uint32_t code;
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ } __packed;
+ } __packed;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "code:\t" << (code) << std::endl;
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
+ CommandTransaction;
+};
+
+class ReadSlot : Command<CommandID::READ_SLOT> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_name[15];
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ union{
+ uint8_t slot_token_id[13]; /** OATH Token Identifier */
+ struct{ /** @see https://openauthentication.org/token-specs/ */
+ uint8_t omp[2];
+ uint8_t tt[2];
+ uint8_t mui[8];
+ uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
+ } slot_token_fields;
+ };
+ union{
+ uint64_t slot_counter;
+ uint8_t slot_counter_s[8];
+ } __packed;
+
+ bool isValid() const { return true; }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(slot_name);
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+
+ ss << "slot_token_id:\t";
+ for (auto i : slot_token_id)
+ ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
+ ss << std::endl;
+ ss << "slot_counter:\t[" << (int)slot_counter << "]\t"
+ << ::nitrokey::misc::hexdump((const uint8_t *)(&slot_counter), sizeof slot_counter, false);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload,
+ struct ResponsePayload> CommandTransaction;
+};
+
+class GetStatus : Command<CommandID::GET_STATUS> {
+ public:
+ struct ResponsePayload {
+ union {
+ uint16_t firmware_version;
+ struct {
+ uint8_t minor;
+ uint8_t major;
+ } firmware_version_st;
+ };
+ union{
+ uint8_t card_serial[4];
+ uint32_t card_serial_u32;
+ } __packed;
+ union {
+ uint8_t general_config[5];
+ struct{
+ uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */
+ uint8_t capslock; /** same as numlock */
+ uint8_t scrolllock; /** same as numlock */
+ uint8_t enable_user_password;
+ uint8_t delete_user_password; /* unused */
+ } __packed;
+ } __packed;
+
+ static constexpr uint8_t special_HOTP_slots = 2;
+ bool isValid() const { return numlock < special_HOTP_slots && capslock < special_HOTP_slots
+ && scrolllock < special_HOTP_slots && enable_user_password < 2; }
+
+ std::string get_card_serial_hex() const {
+ return nitrokey::misc::toHex(card_serial_u32);
+ }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "firmware_version:\t"
+ << "[" << firmware_version << "]" << "\t"
+ << ::nitrokey::misc::hexdump(
+ (const uint8_t *)(&firmware_version), sizeof firmware_version, false);
+ ss << "card_serial_u32:\t" << std::hex << card_serial_u32 << std::endl;
+ ss << "card_serial:\t"
+ << ::nitrokey::misc::hexdump((const uint8_t *)(card_serial),
+ sizeof card_serial, false);
+ ss << "general_config:\t"
+ << ::nitrokey::misc::hexdump((const uint8_t *)(general_config),
+ sizeof general_config, false);
+ ss << "numlock:\t" << (int)numlock << std::endl;
+ ss << "capslock:\t" << (int)capslock << std::endl;
+ ss << "scrolllock:\t" << (int)scrolllock << std::endl;
+ ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl;
+ ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl;
+
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
+ CommandTransaction;
+};
+
+class GetPasswordRetryCount : Command<CommandID::GET_PASSWORD_RETRY_COUNT> {
+ public:
+ struct ResponsePayload {
+ uint8_t password_retry_count;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " password_retry_count\t" << (int)password_retry_count << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
+ CommandTransaction;
+};
+
+class GetUserPasswordRetryCount
+ : Command<CommandID::GET_USER_PASSWORD_RETRY_COUNT> {
+ public:
+ struct ResponsePayload {
+ uint8_t password_retry_count;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " password_retry_count\t" << (int)password_retry_count << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
+ CommandTransaction;
+};
+
+ template <typename T, typename Q, int N>
+ void write_array(T &ss, Q (&arr)[N]){
+ for (int i=0; i<N; i++){
+ ss << std::hex << std::setfill('0') << std::setw(2) << (int)arr[i] << " ";
+ }
+ ss << std::endl;
+ };
+
+
+class GetPasswordSafeSlotStatus : Command<CommandID::GET_PW_SAFE_SLOT_STATUS> {
+ public:
+ struct ResponsePayload {
+ uint8_t password_safe_status[PWS_SLOT_COUNT];
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "password_safe_status\t";
+ write_array(ss, password_safe_status);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
+ CommandTransaction;
+};
+
+class GetPasswordSafeSlotName : Command<CommandID::GET_PW_SAFE_SLOT_NAME> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number\t" << (int)slot_number << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_name[PWS_SLOTNAME_LENGTH];
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(slot_name);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload,
+ struct ResponsePayload> CommandTransaction;
+};
+
+class GetPasswordSafeSlotPassword
+ : Command<CommandID::GET_PW_SAFE_SLOT_PASSWORD> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " slot_number\t" << (int)slot_number << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_password[PWS_PASSWORD_LENGTH];
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(slot_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload,
+ struct ResponsePayload> CommandTransaction;
+};
+
+class GetPasswordSafeSlotLogin
+ : Command<CommandID::GET_PW_SAFE_SLOT_LOGINNAME> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " slot_number\t" << (int)slot_number << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_login[PWS_LOGINNAME_LENGTH];
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(slot_login);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload,
+ struct ResponsePayload> CommandTransaction;
+};
+
+class SetPasswordSafeSlotData : Command<CommandID::SET_PW_SAFE_SLOT_DATA_1> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint8_t slot_name[PWS_SLOTNAME_LENGTH];
+ uint8_t slot_password[PWS_PASSWORD_LENGTH];
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " slot_number\t" << (int)slot_number << std::endl;
+ print_to_ss_volatile(slot_name);
+ print_to_ss_volatile(slot_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class SetPasswordSafeSlotData2 : Command<CommandID::SET_PW_SAFE_SLOT_DATA_2> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint8_t slot_login_name[PWS_LOGINNAME_LENGTH];
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " slot_number\t" << (int)slot_number << std::endl;
+ print_to_ss_volatile(slot_login_name);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class ErasePasswordSafeSlot : Command<CommandID::PW_SAFE_ERASE_SLOT> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " slot_number\t" << (int)slot_number << std::endl;
+ return ss.str();
+ }
+
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class EnablePasswordSafe : Command<CommandID::PW_SAFE_ENABLE> {
+ public:
+ struct CommandPayload {
+ uint8_t user_password[30];
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(user_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class PasswordSafeInitKey : Command<CommandID::PW_SAFE_INIT_KEY> {
+ /**
+ * never used in Nitrokey App
+ */
+ public:
+ typedef Transaction<command_id(), struct EmptyPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class PasswordSafeSendSlotViaHID : Command<CommandID::PW_SAFE_SEND_DATA> {
+ /**
+ * never used in Nitrokey App
+ */
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint8_t slot_kind;
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+// TODO "Device::passwordSafeSendSlotDataViaHID"
+
+class WriteGeneralConfig : Command<CommandID::WRITE_CONFIG> {
+ public:
+ struct CommandPayload {
+ union{
+ uint8_t config[5];
+ struct{
+ uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */
+ uint8_t capslock; /** same as numlock */
+ uint8_t scrolllock; /** same as numlock */
+ uint8_t enable_user_password;
+ uint8_t delete_user_password;
+ };
+ };
+ bool isValid() const { return numlock < 2 && capslock < 2 && scrolllock < 2 && enable_user_password < 2; }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "numlock:\t" << (int)numlock << std::endl;
+ ss << "capslock:\t" << (int)capslock << std::endl;
+ ss << "scrolllock:\t" << (int)scrolllock << std::endl;
+ ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl;
+ ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class FirstAuthenticate : Command<CommandID::FIRST_AUTHENTICATE> {
+ public:
+ struct CommandPayload {
+ uint8_t card_password[25];
+ uint8_t temporary_password[25];
+
+ bool isValid() const { return true; }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(card_password);
+ hexdump_to_ss(temporary_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class UserAuthenticate : Command<CommandID::USER_AUTHENTICATE> {
+ public:
+ struct CommandPayload {
+ uint8_t card_password[25];
+ uint8_t temporary_password[25];
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(card_password);
+ hexdump_to_ss(temporary_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class Authorize : Command<CommandID::AUTHORIZE> {
+ public:
+ struct CommandPayload {
+ uint32_t crc_to_authorize;
+ uint8_t temporary_password[25];
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " crc_to_authorize:\t" << std::hex << std::setw(2) << std::setfill('0') << crc_to_authorize<< std::endl;
+ hexdump_to_ss(temporary_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class UserAuthorize : Command<CommandID::USER_AUTHORIZE> {
+ public:
+ struct CommandPayload {
+ uint32_t crc_to_authorize;
+ uint8_t temporary_password[25];
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << " crc_to_authorize:\t" << crc_to_authorize<< std::endl;
+ hexdump_to_ss(temporary_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class UnlockUserPassword : Command<CommandID::UNLOCK_USER_PASSWORD> {
+ public:
+ struct CommandPayload {
+ uint8_t admin_password[25];
+ uint8_t user_new_password[25];
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(admin_password);
+ print_to_ss_volatile(user_new_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class ChangeUserPin : Command<CommandID::CHANGE_USER_PIN> {
+ public:
+ struct CommandPayload {
+ uint8_t old_pin[25];
+ uint8_t new_pin[25];
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(old_pin);
+ print_to_ss_volatile(new_pin);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class IsAESSupported : Command<CommandID::DETECT_SC_AES> {
+ public:
+ struct CommandPayload {
+ uint8_t user_password[20];
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(user_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+
+class ChangeAdminPin : Command<CommandID::CHANGE_ADMIN_PIN> {
+ public:
+ struct CommandPayload {
+ uint8_t old_pin[25];
+ uint8_t new_pin[25];
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(old_pin);
+ print_to_ss_volatile(new_pin);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class LockDevice : Command<CommandID::LOCK_DEVICE> {
+ public:
+ typedef Transaction<command_id(), struct EmptyPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class FactoryReset : Command<CommandID::FACTORY_RESET> {
+ public:
+ struct CommandPayload {
+ uint8_t admin_password[20];
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(admin_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+};
+
+class BuildAESKey : Command<CommandID::NEW_AES_KEY> {
+ public:
+ struct CommandPayload {
+ uint8_t admin_password[20];
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile(admin_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+
+};
+
+}
+}
+}
+#pragma pack (pop)
+#endif
diff --git a/libnitrokey-3.3/libnitrokey/stick10_commands_0.8.h b/libnitrokey-3.3/libnitrokey/stick10_commands_0.8.h
new file mode 100644
index 0000000..9477890
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/stick10_commands_0.8.h
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+
+#ifndef LIBNITROKEY_STICK10_COMMANDS_0_8_H
+#define LIBNITROKEY_STICK10_COMMANDS_0_8_H
+
+#include <bitset>
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <cstdint>
+#include "command.h"
+#include "device_proto.h"
+#include "stick10_commands.h"
+
+#pragma pack (push,1)
+
+
+namespace nitrokey {
+ namespace proto {
+
+/*
+ * Stick10 protocol definition
+ */
+ namespace stick10_08 {
+ using stick10::FirstAuthenticate;
+ using stick10::UserAuthenticate;
+ using stick10::SetTime;
+ using stick10::GetStatus;
+ using stick10::BuildAESKey;
+ using stick10::ChangeAdminPin;
+ using stick10::ChangeUserPin;
+ using stick10::EnablePasswordSafe;
+ using stick10::ErasePasswordSafeSlot;
+ using stick10::FactoryReset;
+ using stick10::GetPasswordRetryCount;
+ using stick10::GetUserPasswordRetryCount;
+ using stick10::GetPasswordSafeSlotLogin;
+ using stick10::GetPasswordSafeSlotName;
+ using stick10::GetPasswordSafeSlotPassword;
+ using stick10::GetPasswordSafeSlotStatus;
+ using stick10::GetSlotName;
+ using stick10::IsAESSupported;
+ using stick10::LockDevice;
+ using stick10::PasswordSafeInitKey;
+ using stick10::PasswordSafeSendSlotViaHID;
+ using stick10::SetPasswordSafeSlotData;
+ using stick10::SetPasswordSafeSlotData2;
+ using stick10::UnlockUserPassword;
+ using stick10::ReadSlot;
+
+ class EraseSlot : Command<CommandID::ERASE_SLOT> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint8_t temporary_admin_password[25];
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ hexdump_to_ss(temporary_admin_password);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+
+ class SendOTPData : Command<CommandID::SEND_OTP_DATA> {
+ //admin auth
+ public:
+ struct CommandPayload {
+ uint8_t temporary_admin_password[25];
+ uint8_t type; //S-secret, N-name
+ uint8_t id; //multiple reports for values longer than 30 bytes
+ uint8_t data[30]; //data, does not need null termination
+
+ bool isValid() const { return true; }
+
+ void setTypeName(){
+ type = 'N';
+ }
+ void setTypeSecret(){
+ type = 'S';
+ }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ hexdump_to_ss(temporary_admin_password);
+ ss << "type:\t" << type << std::endl;
+ ss << "id:\t" << (int)id << std::endl;
+#ifdef LOG_VOLATILE_DATA
+ ss << "data:" << std::endl
+ << ::nitrokey::misc::hexdump((const uint8_t *) (&data), sizeof data);
+#else
+ ss << " Volatile data not logged" << std::endl;
+#endif
+ return ss.str();
+ }
+ } __packed;
+
+
+ struct ResponsePayload {
+ union {
+ uint8_t data[40];
+ } __packed;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+#ifdef LOG_VOLATILE_DATA
+ ss << "data:" << std::endl
+ << ::nitrokey::misc::hexdump((const uint8_t *) (&data), sizeof data);
+#else
+ ss << " Volatile data not logged" << std::endl;
+#endif
+ return ss.str();
+ }
+ } __packed;
+
+
+ typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
+ CommandTransaction;
+ };
+
+ class WriteToOTPSlot : Command<CommandID::WRITE_TO_SLOT> {
+ //admin auth
+ public:
+ struct CommandPayload {
+ uint8_t temporary_admin_password[25];
+ uint8_t slot_number;
+ union {
+ uint64_t slot_counter_or_interval;
+ uint8_t slot_counter_s[8];
+ } __packed;
+ union {
+ uint8_t _slot_config;
+ struct {
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ union {
+ uint8_t slot_token_id[13]; /** OATH Token Identifier */
+ struct { /** @see https://openauthentication.org/token-specs/ */
+ uint8_t omp[2];
+ uint8_t tt[2];
+ uint8_t mui[8];
+ uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
+ } slot_token_fields;
+ };
+
+ bool isValid() const { return true; }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ hexdump_to_ss(temporary_admin_password);
+ ss << "slot_config:\t" << std::bitset<8>((int) _slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+ ss << "slot_number:\t" << (int) (slot_number) << std::endl;
+ ss << "slot_counter_or_interval:\t[" << (int) slot_counter_or_interval << "]\t"
+ << ::nitrokey::misc::hexdump((const uint8_t *) (&slot_counter_or_interval), sizeof slot_counter_or_interval, false);
+
+ ss << "slot_token_id:\t";
+ for (auto i : slot_token_id)
+ ss << std::hex << std::setw(2) << std::setfill('0') << (int) i << " ";
+ ss << std::endl;
+
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+
+ class GetHOTP : Command<CommandID::GET_CODE> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ struct {
+ uint64_t challenge; //@unused
+ uint64_t last_totp_time; //@unused
+ uint8_t last_interval; //@unused
+ } __packed _unused;
+ uint8_t temporary_user_password[25];
+
+ bool isValid() const { return (slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ hexdump_to_ss(temporary_user_password);
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ union {
+ uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
+ struct {
+ uint32_t code;
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ } __packed;
+ } __packed;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "code:\t" << (code) << std::endl;
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
+ CommandTransaction;
+ };
+
+
+ class GetTOTP : Command<CommandID::GET_CODE> {
+ //user auth
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint64_t challenge; //@unused
+ uint64_t last_totp_time; //@unused
+ uint8_t last_interval; //@unused
+ uint8_t temporary_user_password[25];
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ hexdump_to_ss(temporary_user_password);
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ ss << "challenge:\t" << (challenge) << std::endl;
+ ss << "last_totp_time:\t" << (last_totp_time) << std::endl;
+ ss << "last_interval:\t" << (int)(last_interval) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ union {
+ uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
+ struct {
+ uint32_t code;
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ } __packed ;
+ } __packed ;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "code:\t" << (code) << std::endl;
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
+ CommandTransaction;
+ };
+
+
+ class WriteGeneralConfig : Command<CommandID::WRITE_CONFIG> {
+ //admin auth
+ public:
+ struct CommandPayload {
+ union{
+ uint8_t config[5];
+ struct{
+ uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */
+ uint8_t capslock; /** same as numlock */
+ uint8_t scrolllock; /** same as numlock */
+ uint8_t enable_user_password;
+ uint8_t delete_user_password;
+ };
+ };
+ uint8_t temporary_admin_password[25];
+
+ static constexpr uint8_t special_HOTP_slots = 3;
+ bool isValid() const { return numlock < special_HOTP_slots && capslock < special_HOTP_slots
+ && scrolllock < special_HOTP_slots && enable_user_password < 2; }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "numlock:\t" << (int)numlock << std::endl;
+ ss << "capslock:\t" << (int)capslock << std::endl;
+ ss << "scrolllock:\t" << (int)scrolllock << std::endl;
+ ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl;
+ ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+ }
+ }
+}
+#pragma pack (pop)
+
+#endif //LIBNITROKEY_STICK10_COMMANDS_0_8_H
diff --git a/libnitrokey-3.3/libnitrokey/stick20_commands.h b/libnitrokey-3.3/libnitrokey/stick20_commands.h
new file mode 100644
index 0000000..4b75e6a
--- /dev/null
+++ b/libnitrokey-3.3/libnitrokey/stick20_commands.h
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2015-2018 Nitrokey UG
+ *
+ * This file is part of libnitrokey.
+ *
+ * libnitrokey is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * libnitrokey is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-3.0
+ */
+
+#ifndef STICK20_COMMANDS_H
+#define STICK20_COMMANDS_H
+
+
+
+#include <cstdint>
+#include "command.h"
+#include <string>
+#include <sstream>
+#include "device_proto.h"
+
+#pragma pack (push,1)
+
+namespace nitrokey {
+ namespace proto {
+
+/*
+* STICK20 protocol command ids
+* a superset (almost) of STICK10
+*/
+
+ namespace stick20 {
+
+ class ChangeAdminUserPin20Current :
+ public PasswordCommand<CommandID::SEND_PASSWORD, PasswordKind::Admin> {};
+ class ChangeAdminUserPin20New :
+ public PasswordCommand<CommandID::SEND_NEW_PASSWORD, PasswordKind::Admin> {};
+ class UnlockUserPin :
+ public PasswordCommand<CommandID::UNLOCK_USER_PASSWORD, PasswordKind::Admin> {};
+
+ class EnableEncryptedPartition : public PasswordCommand<CommandID::ENABLE_CRYPTED_PARI> {};
+ class EnableHiddenEncryptedPartition : public PasswordCommand<CommandID::ENABLE_HIDDEN_CRYPTED_PARI> {};
+
+ class SetUnencryptedVolumeReadOnlyAdmin :
+ public PasswordCommand<CommandID::ENABLE_ADMIN_READONLY_UNCRYPTED_LUN, PasswordKind::Admin> {};
+ class SetUnencryptedVolumeReadWriteAdmin :
+ public PasswordCommand<CommandID::ENABLE_ADMIN_READWRITE_UNCRYPTED_LUN, PasswordKind::Admin> {};
+ class SetEncryptedVolumeReadOnly :
+ public PasswordCommand<CommandID::ENABLE_ADMIN_READONLY_ENCRYPTED_LUN, PasswordKind::Admin> {};
+ class SetEncryptedVolumeReadWrite :
+ public PasswordCommand<CommandID::ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN, PasswordKind::Admin> {};
+
+ //FIXME the volume disabling commands do not need password
+ class DisableEncryptedPartition : public PasswordCommand<CommandID::DISABLE_CRYPTED_PARI> {};
+ class DisableHiddenEncryptedPartition : public PasswordCommand<CommandID::DISABLE_HIDDEN_CRYPTED_PARI> {};
+
+ class EnableFirmwareUpdate : public PasswordCommand<CommandID::ENABLE_FIRMWARE_UPDATE> {};
+
+ class ChangeUpdatePassword : Command<CommandID::CHANGE_UPDATE_PIN> {
+ public:
+ struct CommandPayload {
+ uint8_t __gap;
+ uint8_t current_update_password[20];
+ uint8_t __gap2;
+ uint8_t new_update_password[20];
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss_volatile( current_update_password );
+ print_to_ss_volatile( new_update_password );
+ return ss.str();
+ }
+ };
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+
+ class ExportFirmware : public PasswordCommand<CommandID::EXPORT_FIRMWARE_TO_FILE> {};
+
+ class CreateNewKeys :
+ public PasswordCommand<CommandID::GENERATE_NEW_KEYS, PasswordKind::AdminPrefixed, 30> {};
+
+
+ class FillSDCardWithRandomChars : Command<CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS> {
+ public:
+ enum class ChosenVolumes : uint8_t {
+ all_volumes = 0,
+ encrypted_volume = 1
+ };
+
+ struct CommandPayload {
+ uint8_t volume_flag;
+ uint8_t kind;
+ uint8_t admin_pin[20];
+
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss( (int) volume_flag );
+ print_to_ss( kind );
+ print_to_ss_volatile(admin_pin);
+ return ss.str();
+ }
+ void set_kind_user() {
+ kind = (uint8_t) 'P';
+ }
+ void set_defaults(){
+ set_kind_user();
+ volume_flag = static_cast<uint8_t>(ChosenVolumes::encrypted_volume);
+ }
+
+ } __packed;
+
+ typedef Transaction<Command<CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS>::command_id(),
+ struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+
+ namespace StorageCommandResponsePayload{
+ using namespace DeviceResponseConstants;
+ static constexpr auto padding_size =
+ storage_data_absolute_address - header_size;
+ struct TransmissionData{
+ uint8_t _padding[padding_size];
+
+ uint8_t SendCounter_u8;
+ uint8_t SendDataType_u8;
+ uint8_t FollowBytesFlag_u8;
+ uint8_t SendSize_u8;
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "_padding:" << std::endl
+ << ::nitrokey::misc::hexdump((const uint8_t *) (_padding),
+ sizeof _padding);
+ print_to_ss((int) SendCounter_u8);
+ print_to_ss((int) SendDataType_u8);
+ print_to_ss((int) FollowBytesFlag_u8);
+ print_to_ss((int) SendSize_u8);
+ return ss.str();
+ }
+
+ } __packed;
+ }
+
+ namespace DeviceConfigurationResponsePacket{
+
+ struct ResponsePayload {
+ StorageCommandResponsePayload::TransmissionData transmission_data;
+
+ uint16_t MagicNumber_StickConfig_u16;
+ /**
+ * READ_WRITE_ACTIVE = ReadWriteFlagUncryptedVolume_u8 == 0;
+ */
+ uint8_t ReadWriteFlagUncryptedVolume_u8;
+ uint8_t ReadWriteFlagCryptedVolume_u8;
+
+ union{
+ uint8_t VersionInfo_au8[4];
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint8_t _reserved2;
+ uint8_t build_iteration;
+ } __packed versionInfo;
+ } __packed;
+
+ uint8_t ReadWriteFlagHiddenVolume_u8;
+ uint8_t FirmwareLocked_u8;
+
+ union{
+ uint8_t NewSDCardFound_u8;
+ struct {
+ bool NewCard :1;
+ uint8_t Counter :7;
+ } __packed NewSDCardFound_st;
+ } __packed;
+
+ /**
+ * SD card FILLED with random chars
+ */
+ uint8_t SDFillWithRandomChars_u8;
+ uint32_t ActiveSD_CardID_u32;
+ union{
+ uint8_t VolumeActiceFlag_u8;
+ struct {
+ bool unencrypted :1;
+ bool encrypted :1;
+ bool hidden :1;
+ } __packed VolumeActiceFlag_st;
+ } __packed;
+ uint8_t NewSmartCardFound_u8;
+ uint8_t UserPwRetryCount;
+ uint8_t AdminPwRetryCount;
+ uint32_t ActiveSmartCardID_u32;
+ uint8_t StickKeysNotInitiated;
+
+ bool isValid() const { return true; }
+
+ std::string dissect() const {
+ std::stringstream ss;
+
+ print_to_ss(transmission_data.dissect());
+ print_to_ss( MagicNumber_StickConfig_u16 );
+ print_to_ss((int) ReadWriteFlagUncryptedVolume_u8 );
+ print_to_ss((int) ReadWriteFlagCryptedVolume_u8 );
+ print_to_ss((int) ReadWriteFlagHiddenVolume_u8 );
+ print_to_ss((int) versionInfo.major );
+ print_to_ss((int) versionInfo.minor );
+ print_to_ss((int) versionInfo.build_iteration );
+ print_to_ss((int) FirmwareLocked_u8 );
+ print_to_ss((int) NewSDCardFound_u8 );
+ print_to_ss((int) NewSDCardFound_st.NewCard );
+ print_to_ss((int) NewSDCardFound_st.Counter );
+ print_to_ss((int) SDFillWithRandomChars_u8 );
+ print_to_ss( ActiveSD_CardID_u32 );
+ print_to_ss((int) VolumeActiceFlag_u8 );
+ print_to_ss((int) VolumeActiceFlag_st.unencrypted );
+ print_to_ss((int) VolumeActiceFlag_st.encrypted );
+ print_to_ss((int) VolumeActiceFlag_st.hidden);
+ print_to_ss((int) NewSmartCardFound_u8 );
+ print_to_ss((int) UserPwRetryCount );
+ print_to_ss((int) AdminPwRetryCount );
+ print_to_ss( ActiveSmartCardID_u32 );
+ print_to_ss((int) StickKeysNotInitiated );
+
+ return ss.str();
+ }
+ } __packed;
+ }
+
+ class SendStartup : Command<CommandID::SEND_STARTUP> {
+ public:
+ struct CommandPayload {
+ uint64_t localtime; // POSIX seconds from epoch start, supports until year 2106
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss( localtime );
+ return ss.str();
+ }
+ void set_defaults(){
+ localtime =
+ std::chrono::duration_cast<std::chrono::seconds> (
+ std::chrono::system_clock::now().time_since_epoch()).count();
+ }
+ }__packed;
+
+ using ResponsePayload = DeviceConfigurationResponsePacket::ResponsePayload;
+
+ typedef Transaction<command_id(), struct CommandPayload, ResponsePayload>
+ CommandTransaction;
+ };
+
+
+// TODO fix original nomenclature
+ class SendSetReadonlyToUncryptedVolume : public PasswordCommand<CommandID::ENABLE_READONLY_UNCRYPTED_LUN> {};
+ class SendSetReadwriteToUncryptedVolume : public PasswordCommand<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN> {};
+ class SendClearNewSdCardFound : public PasswordCommand<CommandID::CLEAR_NEW_SD_CARD_FOUND> {};
+
+ class GetDeviceStatus : Command<CommandID::GET_DEVICE_STATUS> {
+ public:
+ using ResponsePayload = DeviceConfigurationResponsePacket::ResponsePayload;
+
+ typedef Transaction<command_id(), struct EmptyPayload, ResponsePayload>
+ CommandTransaction;
+ };
+
+ class CheckSmartcardUsage : Command<CommandID::CHECK_SMARTCARD_USAGE> {
+ public:
+ typedef Transaction<command_id(), struct EmptyPayload, EmptyPayload>
+ CommandTransaction;
+ };
+
+ class GetSDCardOccupancy : Command<CommandID::SD_CARD_HIGH_WATERMARK> {
+ public:
+ struct ResponsePayload {
+ uint8_t WriteLevelMin;
+ uint8_t WriteLevelMax;
+ uint8_t ReadLevelMin;
+ uint8_t ReadLevelMax;
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss((int) WriteLevelMin);
+ print_to_ss((int) WriteLevelMax);
+ print_to_ss((int) ReadLevelMin);
+ print_to_ss((int) ReadLevelMax);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
+ CommandTransaction;
+ };
+
+
+ class SetupHiddenVolume : Command<CommandID::SEND_HIDDEN_VOLUME_SETUP> {
+ public:
+ constexpr static int MAX_HIDDEN_VOLUME_PASSWORD_SIZE = 20;
+ struct CommandPayload {
+ uint8_t SlotNr_u8;
+ uint8_t StartBlockPercent_u8;
+ uint8_t EndBlockPercent_u8;
+ uint8_t HiddenVolumePassword_au8[MAX_HIDDEN_VOLUME_PASSWORD_SIZE];
+ std::string dissect() const {
+ std::stringstream ss;
+ print_to_ss((int) SlotNr_u8);
+ print_to_ss((int) StartBlockPercent_u8);
+ print_to_ss((int) EndBlockPercent_u8);
+ print_to_ss_volatile(HiddenVolumePassword_au8);
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+
+
+//disable this command for now
+// class LockFirmware : public PasswordCommand<CommandID::SEND_LOCK_STICK_HARDWARE> {};
+
+ class ProductionTest : Command<CommandID::PRODUCTION_TEST> {
+ public:
+ struct ResponsePayload {
+
+ StorageCommandResponsePayload::TransmissionData transmission_data;
+
+ uint8_t FirmwareVersion_au8[2]; // 2 byte // 2
+ uint8_t FirmwareVersionInternal_u8; // 1 byte // 3
+ uint8_t SD_Card_Size_u8; // 1 byte // 4
+ uint32_t CPU_CardID_u32; // 4 byte // 8
+ uint32_t SmartCardID_u32; // 4 byte // 12
+ uint32_t SD_CardID_u32; // 4 byte // 16
+ uint8_t SC_UserPwRetryCount; // User PIN retry count 1 byte // 17
+ uint8_t SC_AdminPwRetryCount; // Admin PIN retry count 1 byte // 18
+ uint8_t SD_Card_ManufacturingYear_u8; // 1 byte // 19
+ uint8_t SD_Card_ManufacturingMonth_u8; // 1 byte // 20
+ uint16_t SD_Card_OEM_u16; // 2 byte // 22
+ uint16_t SD_WriteSpeed_u16; // in kbyte / sec 2 byte // 24
+ uint8_t SD_Card_Manufacturer_u8; // 1 byte // 25
+
+ bool isValid() const { return true; }
+
+ std::string dissect() const {
+ std::stringstream ss;
+
+ print_to_ss(transmission_data.dissect());
+ print_to_ss((int) FirmwareVersion_au8[0]);
+ print_to_ss((int) FirmwareVersion_au8[1]);
+ print_to_ss((int) FirmwareVersionInternal_u8);
+ print_to_ss((int) SD_Card_Size_u8);
+ print_to_ss( CPU_CardID_u32);
+ print_to_ss( SmartCardID_u32);
+ print_to_ss( SD_CardID_u32);
+ print_to_ss((int) SC_UserPwRetryCount);
+ print_to_ss((int) SC_AdminPwRetryCount);
+ print_to_ss((int) SD_Card_ManufacturingYear_u8);
+ print_to_ss((int) SD_Card_ManufacturingMonth_u8);
+ print_to_ss( SD_Card_OEM_u16);
+ print_to_ss( SD_WriteSpeed_u16);
+ print_to_ss((int) SD_Card_Manufacturer_u8);
+ return ss.str();
+ }
+
+ } __packed;
+
+ typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
+ CommandTransaction;
+ };
+
+ }
+ }
+}
+
+#undef print_to_ss
+#pragma pack (pop)
+
+#endif