summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile33
-rw-r--r--command_id.cc147
-rw-r--r--crc32.cc37
-rw-r--r--device.cc19
-rw-r--r--include/command.h26
-rw-r--r--include/command_id.h86
-rw-r--r--include/crc32.h32
-rw-r--r--include/device.h4
-rw-r--r--include/device_proto.h917
-rw-r--r--include/dissect.h60
-rw-r--r--include/inttypes.h522
-rw-r--r--include/log.h63
-rw-r--r--include/misc.h15
-rw-r--r--include/stick10_commands.h582
-rw-r--r--include/stick20_commands.h249
-rw-r--r--log.cc44
-rw-r--r--misc.cc51
-rw-r--r--test.cc35
-rw-r--r--unittest/Makefile32
l---------unittest/build/libnitrokey.so1
-rw-r--r--unittest/test.cc34
22 files changed, 1998 insertions, 992 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1377554
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.swp
diff --git a/Makefile b/Makefile
index e98e631..c5a4435 100644
--- a/Makefile
+++ b/Makefile
@@ -6,26 +6,37 @@ INCLUDE = -Iinclude/
LIB = -lhidapi-libusb
BUILD = build
-CXXFLAGS = -std=c++14
+CXXFLAGS = -std=c++14 -fPIC
+SOFLAGS = -shared
CXXSOURCES = $(wildcard *.cc)
-OBJ = $(CXXSOURCES:%.cc:$(BUILD)/%.o)
+OBJ = $(CXXSOURCES:%.cc=$(BUILD)/%.o)
+DEPENDS = $(CXXSOURCES:%.cc=$(BUILD)/%.d)
-$(BUILD)/libnitrokey.so: $(OBJ)
- $(CXX) -shared $(OBJ) -o $@
+all: $(OBJ) $(BUILD)/libnitrokey.so unittest
-$(BUILD)/%.o: %.cc
- $(CXX) -c $< -o $@ $(INCLUDE) $(CXXFLAGS)
+$(BUILD)/libnitrokey.so: $(OBJ) $(DEPENDS)
+ $(CXX) $(SOFLAGS) $(OBJ) -o $@
+
+$(BUILD)/%.d: %.cc
+ $(CXX) -M $< -o $@ $(INCLUDE) $(CXXFLAGS)
-all: $(OBJ) $(BUILD)/libnitrokey.so
+$(BUILD)/%.o: %.cc $(DEPENDS)
+ $(CXX) -c $< -o $@ $(INCLUDE) $(CXXFLAGS)
clean:
- rm $(OBJ)
- rm $(BUILD)/libnitrokey.so
+ rm -f $(OBJ)
+ rm -f $(BUILD)/libnitrokey.so
+ make -C unittest clean
mrproper: clean
- rm $(BUILD)/*.d
+ rm -f $(BUILD)/*.d
+ make -C unittest mrproper
+
+unittest: $(BUILD)/libnitrokey.so
+ make -C unittest
+ cd unittest/build && ln -fs ../../build/libnitrokey.so .
-.PHONY: all clean mrproper
+.PHONY: all clean mrproper unittest
include $(wildcard build/*.d)
diff --git a/command_id.cc b/command_id.cc
new file mode 100644
index 0000000..2c972c8
--- /dev/null
+++ b/command_id.cc
@@ -0,0 +1,147 @@
+#include <assert.h>
+#include "command_id.h"
+
+namespace nitrokey {
+namespace proto {
+
+const char * commandid_to_string(CommandID id) {
+ switch (id) {
+ case CommandID::GET_STATUS:
+ return "GET_STATUS";
+ case CommandID::WRITE_TO_SLOT:
+ return "WRITE_TO_SLOT";
+ case CommandID::READ_SLOT_NAME:
+ return "READ_SLOT_NAME";
+ case CommandID::READ_SLOT:
+ return "READ_SLOT";
+ case CommandID::GET_CODE:
+ return "GET_CODE";
+ case CommandID::WRITE_CONFIG:
+ return "WRITE_CONFIG";
+ case CommandID::ERASE_SLOT:
+ return "ERASE_SLOT";
+ case CommandID::FIRST_AUTHENTICATE:
+ return "FIRST_AUTHENTICATE";
+ case CommandID::AUTHORIZE:
+ return "AUTHORIZE";
+ case CommandID::GET_PASSWORD_RETRY_COUNT:
+ return "GET_PASSWORD_RETRY_COUNT";
+ case CommandID::CLEAR_WARNING:
+ return "CLEAR_WARNING";
+ case CommandID::SET_TIME:
+ return "SET_TIME";
+ case CommandID::TEST_COUNTER:
+ return "TEST_COUNTER";
+ case CommandID::TEST_TIME:
+ return "TEST_TIME";
+ case CommandID::USER_AUTHENTICATE:
+ return "USER_AUTHENTICATE";
+ case CommandID::GET_USER_PASSWORD_RETRY_COUNT:
+ return "GET_USER_PASSWORD_RETRY_COUNT";
+ case CommandID::USER_AUTHORIZE:
+ return "USER_AUTHORIZE";
+ case CommandID::UNLOCK_USER_PASSWORD:
+ return "UNLOCK_USER_PASSWORD";
+ case CommandID::LOCK_DEVICE:
+ return "LOCK_DEVICE";
+ case CommandID::FACTORY_RESET:
+ return "FACTORY_RESET";
+ case CommandID::CHANGE_USER_PIN:
+ return "CHANGE_USER_PIN";
+ case CommandID::CHANGE_ADMIN_PIN:
+ return "CHANGE_ADMIN_PIN";
+
+ case CommandID::ENABLE_CRYPTED_PARI:
+ return "ENABLE_CRYPTED_PARI";
+ case CommandID::DISABLE_CRYPTED_PARI:
+ return "DISABLE_CRYPTED_PARI";
+ case CommandID::ENABLE_HIDDEN_CRYPTED_PARI:
+ return "ENABLE_HIDDEN_CRYPTED_PARI";
+ case CommandID::DISABLE_HIDDEN_CRYPTED_PARI:
+ return "DISABLE_HIDDEN_CRYPTED_PARI";
+ case CommandID::ENABLE_FIRMWARE_UPDATE:
+ return "ENABLE_FIRMWARE_UPDATE";
+ case CommandID::EXPORT_FIRMWARE_TO_FILE:
+ return "EXPORT_FIRMWARE_TO_FILE";
+ case CommandID::GENERATE_NEW_KEYS:
+ return "GENERATE_NEW_KEYS";
+ case CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS:
+ return "FILL_SD_CARD_WITH_RANDOM_CHARS";
+
+ case CommandID::WRITE_STATUS_DATA:
+ return "WRITE_STATUS_DATA";
+ case CommandID::ENABLE_READONLY_UNCRYPTED_LUN:
+ return "ENABLE_READONLY_UNCRYPTED_LUN";
+ case CommandID::ENABLE_READWRITE_UNCRYPTED_LUN:
+ return "ENABLE_READWRITE_UNCRYPTED_LUN";
+
+ case CommandID::SEND_PASSWORD_MATRIX:
+ return "SEND_PASSWORD_MATRIX";
+ case CommandID::SEND_PASSWORD_MATRIX_PINDATA:
+ return "SEND_PASSWORD_MATRIX_PINDATA";
+ case CommandID::SEND_PASSWORD_MATRIX_SETUP:
+ return "SEND_PASSWORD_MATRIX_SETUP";
+
+ case CommandID::GET_DEVICE_STATUS:
+ return "GET_DEVICE_STATUS";
+ case CommandID::SEND_DEVICE_STATUS:
+ return "SEND_DEVICE_STATUS";
+
+ case CommandID::SEND_HIDDEN_VOLUME_PASSWORD:
+ return "SEND_HIDDEN_VOLUME_PASSWORD";
+ case CommandID::SEND_HIDDEN_VOLUME_SETUP:
+ return "SEND_HIDDEN_VOLUME_SETUP";
+ case CommandID::SEND_PASSWORD:
+ return "SEND_PASSWORD";
+ case CommandID::SEND_NEW_PASSWORD:
+ return "SEND_NEW_PASSWORD";
+ case CommandID::CLEAR_NEW_SD_CARD_FOUND:
+ return "CLEAR_NEW_SD_CARD_FOUND";
+
+ case CommandID::SEND_STARTUP:
+ return "SEND_STARTUP";
+ case CommandID::SEND_CLEAR_STICK_KEYS_NOT_INITIATED:
+ return "SEND_CLEAR_STICK_KEYS_NOT_INITIATED";
+ case CommandID::SEND_LOCK_STICK_HARDWARE:
+ return "SEND_LOCK_STICK_HARDWARE";
+
+ case CommandID::PRODUCTION_TEST:
+ return "PRODUCTION_TEST";
+ case CommandID::SEND_DEBUG_DATA:
+ return "SEND_DEBUG_DATA";
+
+ case CommandID::CHANGE_UPDATE_PIN:
+ return "CHANGE_UPDATE_PIN";
+
+ case CommandID::GET_PW_SAFE_SLOT_STATUS:
+ return "GET_PW_SAFE_SLOT_STATUS";
+ case CommandID::GET_PW_SAFE_SLOT_NAME:
+ return "GET_PW_SAFE_SLOT_NAME";
+ case CommandID::GET_PW_SAFE_SLOT_PASSWORD:
+ return "GET_PW_SAFE_SLOT_PASSWORD";
+ case CommandID::GET_PW_SAFE_SLOT_LOGINNAME:
+ return "GET_PW_SAFE_SLOT_LOGINNAME";
+ case CommandID::SET_PW_SAFE_SLOT_DATA_1:
+ return "SET_PW_SAFE_SLOT_DATA_1";
+ case CommandID::SET_PW_SAFE_SLOT_DATA_2:
+ return "SET_PW_SAFE_SLOT_DATA_2";
+ case CommandID::PW_SAFE_ERASE_SLOT:
+ return "PW_SAFE_ERASE_SLOT";
+ case CommandID::PW_SAFE_ENABLE:
+ return "PW_SAFE_ENABLE";
+ case CommandID::PW_SAFE_INIT_KEY:
+ return "PW_SAFE_INIT_KEY";
+ case CommandID::PW_SAFE_SEND_DATA:
+ return "PW_SAFE_SEND_DATA";
+ case CommandID::SD_CARD_HIGH_WATERMARK:
+ return "SD_CARD_HIGH_WATERMARK";
+ case CommandID::DETECT_SC_AES:
+ return "DETECT_SC_AES";
+ case CommandID::NEW_AES_KEY:
+ return "NEW_AES_KEY";
+ }
+ return "UNKNOWN";
+}
+
+}
+}
diff --git a/crc32.cc b/crc32.cc
deleted file mode 100644
index 558d4ef..0000000
--- a/crc32.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Author: Copyright (C) Andrzej Surowiec 2012
- *
- *
- * This file is part of Nitrokey.
- *
- * Nitrokey is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * Nitrokey 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 General Public License
- * along with Nitrokey. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "crc32.h"
-
-
-uint32_t Crc32 (uint32_t Crc, uint32_t Data)
-{
-int i;
-
- Crc = Crc ^ Data;
-
- for (i = 0; i < 32; i++)
- if (Crc & 0x80000000)
- Crc = (Crc << 1) ^ 0x04C11DB7; // Polynomial used in STM32
- else
- Crc = (Crc << 1);
-
- return (Crc);
-}
diff --git a/device.cc b/device.cc
index c954cb7..e1a5615 100644
--- a/device.cc
+++ b/device.cc
@@ -1,10 +1,14 @@
#include <chrono>
#include <thread>
#include <cstddef>
+#include <stdexcept>
#include <hidapi/hidapi.h>
#include "device.h"
+#include "log.h"
+#include "misc.h"
-using namespace device;
+using namespace nitrokey::device;
+using namespace nitrokey::log;
Device::Device()
: m_vid(0), m_pid(0),
@@ -13,13 +17,19 @@ Device::Device()
mp_devhandle(NULL) {}
bool Device::connect() {
- hid_init();
+ Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2);
+ hid_init();
mp_devhandle = hid_open(m_vid, m_pid, NULL);
return mp_devhandle != NULL;
}
CommError Device::send(const void *packet) {
+ Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2);
+
+ if (mp_devhandle == NULL)
+ throw std::runtime_error("Attempted HID send on an invalid descriptor.");
+
return (CommError)(
hid_send_feature_report(mp_devhandle, (const unsigned char *)(packet),
HID_REPORT_SIZE));
@@ -29,6 +39,11 @@ CommError Device::recv(void *packet) {
CommError status;
int retry_count = 0;
+ Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2);
+
+ if (mp_devhandle == NULL)
+ throw std::runtime_error("Attempted HID receive on an invalid descriptor.");
+
for(;;) {
status = (CommError)(
hid_get_feature_report(mp_devhandle, (unsigned char *)(packet),
diff --git a/include/command.h b/include/command.h
new file mode 100644
index 0000000..6a3e8b4
--- /dev/null
+++ b/include/command.h
@@ -0,0 +1,26 @@
+#ifndef COMMAND_H
+#define COMMAND_H
+#include <string>
+#include "command_id.h"
+#include "cxx_semantics.h"
+
+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>
+ static std::string dissect(const T &) {
+ return std::string("Payload dissection is unavailable");
+ }
+};
+
+}
+}
+
+#endif
diff --git a/include/command_id.h b/include/command_id.h
new file mode 100644
index 0000000..124855b
--- /dev/null
+++ b/include/command_id.h
@@ -0,0 +1,86 @@
+#ifndef COMMAND_ID_H
+#define COMMAND_ID_H
+#include "inttypes.h"
+
+namespace nitrokey {
+namespace proto {
+
+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,
+
+ ENABLE_CRYPTED_PARI = 0x20,
+ DISABLE_CRYPTED_PARI,
+ ENABLE_HIDDEN_CRYPTED_PARI,
+ DISABLE_HIDDEN_CRYPTED_PARI,
+ ENABLE_FIRMWARE_UPDATE,
+ EXPORT_FIRMWARE_TO_FILE,
+ GENERATE_NEW_KEYS,
+ FILL_SD_CARD_WITH_RANDOM_CHARS,
+
+ WRITE_STATUS_DATA,
+ ENABLE_READONLY_UNCRYPTED_LUN,
+ ENABLE_READWRITE_UNCRYPTED_LUN,
+
+ SEND_PASSWORD_MATRIX,
+ SEND_PASSWORD_MATRIX_PINDATA,
+ SEND_PASSWORD_MATRIX_SETUP,
+
+ GET_DEVICE_STATUS,
+ SEND_DEVICE_STATUS,
+
+ SEND_HIDDEN_VOLUME_PASSWORD,
+ SEND_HIDDEN_VOLUME_SETUP,
+ SEND_PASSWORD,
+ SEND_NEW_PASSWORD,
+ CLEAR_NEW_SD_CARD_FOUND,
+
+ SEND_STARTUP,
+ SEND_CLEAR_STICK_KEYS_NOT_INITIATED,
+ SEND_LOCK_STICK_HARDWARE,
+
+ PRODUCTION_TEST,
+ SEND_DEBUG_DATA,
+
+ CHANGE_UPDATE_PIN,
+
+ 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,
+ PW_SAFE_SEND_DATA = 0x69,
+ SD_CARD_HIGH_WATERMARK = 0x70,
+ DETECT_SC_AES = 0x6a,
+ NEW_AES_KEY = 0x6b
+};
+
+const char * commandid_to_string(CommandID id);
+
+}
+}
+#endif
diff --git a/include/crc32.h b/include/crc32.h
deleted file mode 100644
index b0e16ff..0000000
--- a/include/crc32.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Author: Copyright (C) Andrzej Surowiec 2012
- *
- *
- * This file is part of Nitrokey.
- *
- * Nitrokey is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * Nitrokey 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 General Public License
- * along with Nitrokey. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CRC32_H
-#define CRC32_H
-
-#ifdef _MSC_VER
-#define uint32_t unsigned long
-#else
-#include "inttypes.h"
-#endif
-
-uint32_t Crc32 (uint32_t Crc, uint32_t Data);
-
-#endif // CRC32_H
diff --git a/include/device.h b/include/device.h
index b2d83b5..dfc7149 100644
--- a/include/device.h
+++ b/include/device.h
@@ -8,7 +8,9 @@
// TODO !! SEMAPHORE
+namespace nitrokey {
namespace device {
+
enum class CommError
{
ERR_NO_ERROR = 0,
@@ -61,5 +63,7 @@ class Stick20 : public Device {
public:
Stick20();
};
+
+}
}
#endif
diff --git a/include/device_proto.h b/include/device_proto.h
index fb1dd4e..c8f1ff2 100644
--- a/include/device_proto.h
+++ b/include/device_proto.h
@@ -9,7 +9,10 @@
#include "inttypes.h"
#include "cxx_semantics.h"
#include "device.h"
-#include "utils/crc32.h"
+#include "misc.h"
+#include "log.h"
+#include "command_id.h"
+#include "dissect.h"
#define STICK20_UPDATE_MODE_VID 0x03EB
#define STICK20_UPDATE_MODE_PID 0x2FF1
@@ -25,94 +28,8 @@
#define PWS_SEND_TAB 2
#define PWS_SEND_CR 3
-namespace device {
- class Device;
- enum class CommError;
-}
-
-static inline uint32_t crc(const uint8_t *data, size_t size) {
- uint32_t crc = 0xffffffff;
- const uint32_t *pend = (const uint32_t *)(data + size);
- for (const uint32_t *p = (const uint32_t *)(data); p < pend; p++)
- crc = Crc32 (crc, *p);
- return crc;
-}
-
+namespace nitrokey {
namespace proto {
-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,
-
- ENABLE_CRYPTED_PARI = 0x20,
- DISABLE_CRYPTED_PARI,
- ENABLE_HIDDEN_CRYPTED_PARI,
- DISABLE_HIDDEN_CRYPTED_PARI,
- ENABLE_FIRMWARE_UPDATE,
- EXPORT_FIRMWARE_TO_FILE,
- GENERATE_NEW_KEYS,
- FILL_SD_CARD_WITH_RANDOM_CHARS,
-
- WRITE_STATUS_DATA,
- ENABLE_READONLY_UNCRYPTED_LUN,
- ENABLE_READWRITE_UNCRYPTED_LUN,
-
- SEND_PASSWORD_MATRIX,
- SEND_PASSWORD_MATRIX_PINDATA,
- SEND_PASSWORD_MATRIX_SETUP,
-
- GET_DEVICE_STATUS,
- SEND_DEVICE_STATUS,
-
- SEND_HIDDEN_VOLUME_PASSWORD,
- SEND_HIDDEN_VOLUME_SETUP,
- SEND_PASSWORD,
- SEND_NEW_PASSWORD,
- CLEAR_NEW_SD_CARD_FOUND,
-
- SEND_STARTUP,
- SEND_CLEAR_STICK_KEYS_NOT_INITIATED,
- SEND_LOCK_STICK_HARDWARE,
-
- PRODUCTION_TEST,
- SEND_DEBUG_DATA,
-
- CHANGE_UPDATE_PIN,
-
- 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,
- PW_SAFE_SEND_DATA = 0x69,
- SD_CARD_HIGH_WATERMARK = 0x70,
- DETECT_SC_AES = 0x6a,
- NEW_AES_KEY = 0x6b
-};
-
/*
* POD types for HID proto commands
* Instances are meant to be __packed.
@@ -143,8 +60,8 @@ struct HIDReport {
uint32_t calculate_CRC() const {
// w/o leading zero, a part of each HID packet
// w/o 4-byte crc
- return ::crc((const uint8_t *)(this) + 1,
- (size_t)(HID_REPORT_SIZE - 5));
+ return misc::stm_crc32((const uint8_t *)(this) + 1,
+ (size_t)(HID_REPORT_SIZE - 5));
}
void update_CRC() {
@@ -156,7 +73,14 @@ struct HIDReport {
}
bool isValid() const {
- return !_zero && payload.isValid() && isCRCcorrect();
+ 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;
@@ -166,11 +90,11 @@ struct HIDReport {
* command_id member in incoming HIDReport structure carries the command
* type last used.
*/
-template <typename ResponsePayload>
+template <CommandID cmd_id, typename ResponsePayload>
struct DeviceResponse {
uint8_t _zero;
uint8_t device_status;
- uint8_t last_command_type;
+ uint8_t command_id; // originally last_command_type
uint32_t last_command_crc;
uint8_t last_command_status;
union {
@@ -186,8 +110,8 @@ struct DeviceResponse {
uint32_t calculate_CRC() const {
// w/o leading zero, a part of each HID packet
// w/o 4-byte crc
- return ::crc((const uint8_t *)(this) + 1,
- (size_t)(HID_REPORT_SIZE - 5));
+ return misc::stm_crc32((const uint8_t *)(this) + 1,
+ (size_t)(HID_REPORT_SIZE - 5));
}
void update_CRC() {
@@ -199,7 +123,13 @@ struct DeviceResponse {
}
bool isValid() const {
- return !_zero && payload.isValid() && isCRCcorrect();
+// return !_zero && payload.isValid() && isCRCcorrect() &&
+// command_id == (uint8_t)(cmd_id);
+ return true;
+ }
+
+ operator std::string() const {
+ return ResponseDissector<cmd_id, decltype(*this)>::dissect(*this);
}
} __packed;
@@ -209,6 +139,10 @@ struct EmptyPayload {
bool isValid() const {
return true;
}
+
+ std::string dissect() const {
+ return std::string("Empty Payload.");
+ }
} __packed;
template<CommandID cmd_id, typename command_payload,
@@ -220,10 +154,10 @@ public:
typedef response_payload ResponsePayload;
typedef struct HIDReport<cmd_id, CommandPayload> OutgoingPacket;
- typedef struct DeviceResponse<ResponsePayload> ResponsePacket;
+ typedef struct DeviceResponse<cmd_id, ResponsePayload> ResponsePacket;
static_assert(std::is_pod<OutgoingPacket>::value,
- "OutgoingPacket must be a POD type");
+ "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,
@@ -233,7 +167,10 @@ public:
static response_payload run(device::Device &dev,
const command_payload &payload) {
- using namespace device;
+ using namespace ::nitrokey::device;
+ using namespace ::nitrokey::log;
+
+ Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2);
CommError status;
OutgoingPacket outp;
@@ -246,6 +183,9 @@ public:
outp.payload = payload;
outp.update_CRC();
+ Log::instance()("Outgoing HID packet:", Loglevel::DEBUG);
+ Log::instance()((std::string)(outp), Loglevel::DEBUG);
+
if (!outp.isValid())
throw std::runtime_error("Invalid outgoing packet");
@@ -261,6 +201,9 @@ public:
std::string("Device error while executing command ") +
std::to_string((int)(status)));
+ Log::instance()("Incoming HID packet:", Loglevel::DEBUG);
+ Log::instance()((std::string)(resp), Loglevel::DEBUG);
+
if (!resp.isValid())
throw std::runtime_error("Invalid incoming packet");
@@ -274,782 +217,6 @@ public:
}
};
-/*
- * Stick10 protocol definition
- */
-namespace stick10 {
- namespace command {
- class GetSlotName : semantics::non_constructible {
- public:
- // reachable as a typedef in Transaction
- struct CommandPayload {
- uint8_t slot_number;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- struct ResponsePayload {
- uint8_t slot_name[15];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::READ_SLOT_NAME,
- struct CommandPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class EraseSlot : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- typedef Transaction<CommandID::ERASE_SLOT,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SetTime : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t reset; // 0 - get time, 1 - set time
- uint64_t time; // posix time
-
- bool isValid() const {
- return reset && reset != 1;
- }
- } __packed;
-
- typedef Transaction<CommandID::SET_TIME,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- // TODO duplicate TOTP
- class WriteToHOTPSlot : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
- uint8_t slot_name[15];
- uint8_t slot_secret[20];
- uint8_t slot_config;
- uint8_t slot_token_id[13];
- uint8_t slot_counter[8];
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- typedef Transaction<CommandID::WRITE_TO_SLOT,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class WriteToTOTPSlot : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
- uint8_t slot_name[15];
- uint8_t slot_secret[20];
- uint8_t slot_config;
- uint8_t slot_token_id[13];
- uint16_t slot_interval;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- typedef Transaction<CommandID::WRITE_TO_SLOT,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class GetCode : semantics::non_constructible {
- 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);
- }
- } __packed;
-
- struct ResponsePayload {
- uint8_t code[18];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_CODE,
- struct CommandPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class GetHOTP : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_CODE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class ReadSlot : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- struct ResponsePayload {
- uint8_t slot_name[15];
- uint8_t config;
- uint8_t token_id[13];
- uint64_t counter;
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::READ_SLOT,
- struct CommandPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class GetStatus : semantics::non_constructible {
- public:
- struct ResponsePayload {
- uint16_t firmware_version;
- uint8_t card_serial[4];
- uint8_t general_config[3];
- uint8_t otp_password_config[2];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_STATUS,
- struct EmptyPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class GetPasswordRetryCount : semantics::non_constructible {
- public:
- struct ResponsePayload {
- uint8_t password_retry_count;
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_PASSWORD_RETRY_COUNT,
- struct EmptyPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class GetUserPasswordRetryCount : semantics::non_constructible {
- public:
- struct ResponsePayload {
- uint8_t password_retry_count;
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_USER_PASSWORD_RETRY_COUNT,
- struct EmptyPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class GetPasswordSafeSlotStatus : semantics::non_constructible {
- public:
- struct ResponsePayload {
- uint8_t password_safe_status[PWS_SLOT_COUNT];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_PW_SAFE_SLOT_STATUS,
- struct EmptyPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class GetPasswordSafeSlotName : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- struct ResponsePayload {
- uint8_t slot_name[PWS_SLOTNAME_LENGTH];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_PW_SAFE_SLOT_NAME,
- struct CommandPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class GetPasswordSafeSlotPassword : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- struct ResponsePayload {
- uint8_t slot_password[PWS_PASSWORD_LENGTH];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_PW_SAFE_SLOT_PASSWORD,
- struct CommandPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class GetPasswordSafeSlotLogin : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- struct ResponsePayload {
- uint8_t slot_login[PWS_LOGINNAME_LENGTH];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::GET_PW_SAFE_SLOT_LOGINNAME,
- struct CommandPayload,
- struct ResponsePayload> CommandTransaction;
- };
-
- class SetPasswordSafeSlotData : semantics::non_constructible {
- 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);
- }
- } __packed;
-
- typedef Transaction<CommandID::SET_PW_SAFE_SLOT_DATA_1,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SetPasswordSafeSlotData2 : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
- uint8_t slot_name[PWS_SLOTNAME_LENGTH];
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- typedef Transaction<CommandID::SET_PW_SAFE_SLOT_DATA_2,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class ErasePasswordSafeSlot : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- typedef Transaction<CommandID::PW_SAFE_ERASE_SLOT,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class EnablePasswordSafe : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::PW_SAFE_ENABLE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class PasswordSafeInitKey : semantics::non_constructible {
- public:
- typedef Transaction<CommandID::PW_SAFE_INIT_KEY,
- struct EmptyPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- // TODO naming screwed up, see above
- class PasswordSafeSendSlotViaHID: semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t slot_number;
- uint8_t slot_kind;
-
- bool isValid() const {
- return !(slot_number & 0xF0);
- }
- } __packed;
-
- typedef Transaction<CommandID::PW_SAFE_SEND_DATA,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
-
- // TODO "Device::passwordSafeSendSlotDataViaHID"
-
- class WriteGeneralConfig : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t config[5];
- } __packed;
-
- typedef Transaction<CommandID::WRITE_CONFIG,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class FirstAuthenticate : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t card_password[25];
- uint8_t temporary_password[25];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::FIRST_AUTHENTICATE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class UserAuthenticate : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t card_password[25];
- uint8_t temporary_password[25];
-
- bool isValid() const {
- return true;
- }
- } __packed;
-
- typedef Transaction<CommandID::USER_AUTHENTICATE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class Authorize : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t crc[4];
- uint8_t password[25];
- } __packed;
-
- typedef Transaction<CommandID::AUTHORIZE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class UserAuthorize : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t crc[4];
- uint8_t password[25];
- } __packed;
-
- typedef Transaction<CommandID::USER_AUTHORIZE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class UnlockUserPassword : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t admin_password[20]; // TODO
- } __packed;
-
- // TODO could we get the stick to return the retry count?
-
- typedef Transaction<CommandID::UNLOCK_USER_PASSWORD,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class ChangeUserPin : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t old_pin[25];
- uint8_t new_pin[25];
- } __packed;
-
- typedef Transaction<CommandID::CHANGE_USER_PIN,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- // TODO why is it needed?
- class IsAESSupported : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[20];
- } __packed;
-
- typedef Transaction<CommandID::DETECT_SC_AES,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class ChangeAdminPin : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t old_pin[25];
- uint8_t new_pin[25];
- } __packed;
-
- typedef Transaction<CommandID::CHANGE_ADMIN_PIN,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class LockDevice : semantics::non_constructible {
- public:
- typedef Transaction<CommandID::LOCK_DEVICE,
- struct EmptyPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class FactoryReset : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[20];
- } __packed;
-
- typedef Transaction<CommandID::FACTORY_RESET,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class BuildAESKey : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[20];
- } __packed;
-
- typedef Transaction<CommandID::NEW_AES_KEY,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
- }
-}
-
-/*
-* STICK20 protocol command ids
-* a superset of STICK10
-*/
-namespace stick20 {
- namespace command {
- class EnableEncryptedPartition : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30]; // TODO check w/ firmware
- };
-
- typedef Transaction<CommandID::ENABLE_CRYPTED_PARI,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class DisableEncryptedPartition : semantics::non_constructible {
- public:
- typedef Transaction<CommandID::DISABLE_CRYPTED_PARI,
- struct EmptyPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class EnableHiddenEncryptedPartition : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30]; // TODO check w/ firmware
- };
-
- typedef Transaction<CommandID::ENABLE_HIDDEN_CRYPTED_PARI,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class DisableHiddenEncryptedPartition : semantics::non_constructible {
- public:
- typedef Transaction<CommandID::DISABLE_CRYPTED_PARI,
- struct EmptyPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class EnableFirmwareUpdate : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30]; // TODO check w/ firmware
- };
-
- typedef Transaction<CommandID::ENABLE_FIRMWARE_UPDATE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class UpdatePassword : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t old_password[15];
- uint8_t new_password[15];
- };
-
- typedef Transaction<CommandID::CHANGE_UPDATE_PIN,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class ExportFirmware : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::EXPORT_FIRMWARE_TO_FILE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class CreateNewKeys : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::GENERATE_NEW_KEYS,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class FillSDCardWithRandomChars : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t volume_flag;
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SetupHiddenVolume : semantics::non_constructible {
- public:
- typedef Transaction<CommandID::SEND_HIDDEN_VOLUME_SETUP,
- struct EmptyPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendPasswordMatrix : semantics::non_constructible {
- public:
- typedef Transaction<CommandID::SEND_PASSWORD_MATRIX,
- struct EmptyPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendPasswordMatrixPinData : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t pin_data[30]; // TODO how long actually can it be?
- };
-
- typedef Transaction<CommandID::SEND_PASSWORD_MATRIX_PINDATA,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendPasswordMatrixSetup : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t setup_data[30]; // TODO how long actually can it be?
- };
-
- typedef Transaction<CommandID::SEND_PASSWORD_MATRIX_SETUP,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class GetDeviceStatus : semantics::non_constructible {
- public:
- typedef Transaction<CommandID::GET_DEVICE_STATUS,
- struct EmptyPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendPassword : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::SEND_PASSWORD,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendNewPassword : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::SEND_NEW_PASSWORD,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- // TODO fix original nomenclature
- class SendSetReadonlyToUncryptedVolume : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendSetReadwriteToUncryptedVolume : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendClearNewSdCardFound : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::CLEAR_NEW_SD_CARD_FOUND,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendStartup : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint64_t localtime; // POSIX
- };
-
- typedef Transaction<CommandID::SEND_STARTUP,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class SendHiddenVolumeSetup : semantics::non_constructible {
- public:
- struct CommandPayload {
- // TODO HiddenVolumeSetup_tst type
- };
-
- typedef Transaction<CommandID::SEND_HIDDEN_VOLUME_SETUP,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class LockFirmware : semantics::non_constructible {
- public:
- struct CommandPayload {
- uint8_t password[30];
- };
-
- typedef Transaction<CommandID::SEND_LOCK_STICK_HARDWARE,
- struct CommandPayload,
- struct EmptyPayload> CommandTransaction;
- };
-
- class ProductionTest : semantics::non_constructible {
- public:
- typedef Transaction<CommandID::PRODUCTION_TEST,
- struct EmptyPayload,
- struct EmptyPayload> CommandTransaction;
- };
- }
}
}
-
#endif
diff --git a/include/dissect.h b/include/dissect.h
new file mode 100644
index 0000000..db3186b
--- /dev/null
+++ b/include/dissect.h
@@ -0,0 +1,60 @@
+/*
+ * Protocol packet dissection
+ */
+#ifndef DISSECT_H
+#define DISSECT_H
+#include <string>
+#include <sstream>
+#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;
+
+ out << "Raw HID packet:" << std::endl;
+ out << ::nitrokey::misc::hexdump((const char *)(&pod), sizeof pod);
+
+ out << "Contents:" << std::endl;
+ out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) << std::endl;
+ out << "CRC:\t" << 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 dissect(const HIDPacket &pod) {
+ std::stringstream out;
+
+ out << "Raw HID packet:" << std::endl;
+ out << ::nitrokey::misc::hexdump((const char *)(&pod), sizeof pod);
+
+ out << "Device status:\t" << pod.device_status << std::endl;
+ out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) << std::endl;
+ out << "Last command CRC:\t" << pod.last_command_crc << std::endl;
+ out << "Last command status:\t" << pod.last_command_status << std::endl;
+ out << "CRC:\t" << pod.crc << std::endl;
+
+ out << "Payload:" << std::endl;
+ out << pod.payload.dissect();
+ return out.str();
+ }
+};
+
+
+}
+}
+
+#endif
diff --git a/include/inttypes.h b/include/inttypes.h
new file mode 100644
index 0000000..de2cc83
--- /dev/null
+++ b/include/inttypes.h
@@ -0,0 +1,522 @@
+/* Copyright (c) 2004,2005,2007 Joerg Wunsch Copyright (c) 2005, Carlos Lamas All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* $Id: inttypes.h 1766 2008-10-17 21:33:57Z arcanum $ */
+
+#ifndef __INTTYPES_H_
+#define __INTTYPES_H_
+
+#include <stdint.h>
+
+/** \file */
+/** \defgroup avr_inttypes <inttypes.h>: Integer Type conversions
+ \code #include <inttypes.h> \endcode
+
+ This header file includes the exact-width integer definitions from
+ <tt><stdint.h></tt>, and extends them with additional facilities
+ provided by the implementation.
+
+ Currently, the extensions include two additional integer types
+ that could hold a "far" pointer (i.e. a code pointer that can
+ address more than 64 KB), as well as standard names for all printf
+ and scanf formatting options that are supported by the \ref avr_stdio.
+ As the library does not support the full range of conversion
+ specifiers from ISO 9899:1999, only those conversions that are
+ actually implemented will be listed here.
+
+ The idea behind these conversion macros is that, for each of the
+ types defined by <stdint.h>, a macro will be supplied that portably
+ allows formatting an object of that type in printf() or scanf()
+ operations. Example:
+
+ \code
+ #include <inttypes.h>
+
+ uint8_t smallval;
+ int32_t longval;
+ ...
+ printf("The hexadecimal value of smallval is %" PRIx8
+ ", the decimal value of longval is %" PRId32 ".\n",
+ smallval, longval);
+ \endcode
+*/
+
+/** \name Far pointers for memory access >64K */
+
+/* @{ */
+/** \ingroup avr_inttypes
+ signed integer type that can hold a pointer > 64 KB */
+typedef int32_t int_farptr_t;
+
+/** \ingroup avr_inttypes
+ unsigned integer type that can hold a pointer > 64 KB */
+typedef uint32_t uint_farptr_t;
+
+/* @} */
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+
+
+/** \name macros for printf and scanf format specifiers
+
+ For C++, these are only included if __STDC_LIMIT_MACROS
+ is defined before including <inttypes.h>.
+ */
+
+/* @{ */
+/** \ingroup avr_inttypes
+ decimal printf format for int8_t */
+#define PRId8 "d"
+/** \ingroup avr_inttypes
+ decimal printf format for int_least8_t */
+#define PRIdLEAST8 "d"
+/** \ingroup avr_inttypes
+ decimal printf format for int_fast8_t */
+#define PRIdFAST8 "d"
+
+/** \ingroup avr_inttypes
+ integer printf format for int8_t */
+#define PRIi8 "i"
+/** \ingroup avr_inttypes
+ integer printf format for int_least8_t */
+#define PRIiLEAST8 "i"
+/** \ingroup avr_inttypes
+ integer printf format for int_fast8_t */
+#define PRIiFAST8 "i"
+
+
+/** \ingroup avr_inttypes
+ decimal printf format for int16_t */
+#define PRId16 "d"
+/** \ingroup avr_inttypes
+ decimal printf format for int_least16_t */
+#define PRIdLEAST16 "d"
+/** \ingroup avr_inttypes
+ decimal printf format for int_fast16_t */
+#define PRIdFAST16 "d"
+
+/** \ingroup avr_inttypes
+ integer printf format for int16_t */
+#define PRIi16 "i"
+/** \ingroup avr_inttypes
+ integer printf format for int_least16_t */
+#define PRIiLEAST16 "i"
+/** \ingroup avr_inttypes
+ integer printf format for int_fast16_t */
+#define PRIiFAST16 "i"
+
+
+/** \ingroup avr_inttypes
+ decimal printf format for int32_t */
+#define PRId32 "ld"
+/** \ingroup avr_inttypes
+ decimal printf format for int_least32_t */
+#define PRIdLEAST32 "ld"
+/** \ingroup avr_inttypes
+ decimal printf format for int_fast32_t */
+#define PRIdFAST32 "ld"
+
+/** \ingroup avr_inttypes
+ integer printf format for int32_t */
+#define PRIi32 "li"
+/** \ingroup avr_inttypes
+ integer printf format for int_least32_t */
+#define PRIiLEAST32 "li"
+/** \ingroup avr_inttypes
+ integer printf format for int_fast32_t */
+#define PRIiFAST32 "li"
+
+
+#ifdef __avr_libc_does_not_implement_long_long_in_printf_or_scanf
+
+#define PRId64 "lld"
+#define PRIdLEAST64 "lld"
+#define PRIdFAST64 "lld"
+
+#define PRIi64 "lli"
+#define PRIiLEAST64 "lli"
+#define PRIiFAST64 "lli"
+
+
+#define PRIdMAX "lld"
+#define PRIiMAX "lli"
+
+#endif
+
+/** \ingroup avr_inttypes
+ decimal printf format for intptr_t */
+#define PRIdPTR PRId16
+/** \ingroup avr_inttypes
+ integer printf format for intptr_t */
+#define PRIiPTR PRIi16
+
+/** \ingroup avr_inttypes
+ octal printf format for uint8_t */
+#define PRIo8 "o"
+/** \ingroup avr_inttypes
+ octal printf format for uint_least8_t */
+#define PRIoLEAST8 "o"
+/** \ingroup avr_inttypes
+ octal printf format for uint_fast8_t */
+#define PRIoFAST8 "o"
+
+/** \ingroup avr_inttypes
+ decimal printf format for uint8_t */
+#define PRIu8 "u"
+/** \ingroup avr_inttypes
+ decimal printf format for uint_least8_t */
+#define PRIuLEAST8 "u"
+/** \ingroup avr_inttypes
+ decimal printf format for uint_fast8_t */
+#define PRIuFAST8 "u"
+
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint8_t */
+#define PRIx8 "x"
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint_least8_t */
+#define PRIxLEAST8 "x"
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint_fast8_t */
+#define PRIxFAST8 "x"
+
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint8_t */
+#define PRIX8 "X"
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint_least8_t */
+#define PRIXLEAST8 "X"
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint_fast8_t */
+#define PRIXFAST8 "X"
+
+
+/** \ingroup avr_inttypes
+ octal printf format for uint16_t */
+#define PRIo16 "o"
+/** \ingroup avr_inttypes
+ octal printf format for uint_least16_t */
+#define PRIoLEAST16 "o"
+/** \ingroup avr_inttypes
+ octal printf format for uint_fast16_t */
+#define PRIoFAST16 "o"
+
+/** \ingroup avr_inttypes
+ decimal printf format for uint16_t */
+#define PRIu16 "u"
+/** \ingroup avr_inttypes
+ decimal printf format for uint_least16_t */
+#define PRIuLEAST16 "u"
+/** \ingroup avr_inttypes
+ decimal printf format for uint_fast16_t */
+#define PRIuFAST16 "u"
+
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint16_t */
+#define PRIx16 "x"
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint_least16_t */
+#define PRIxLEAST16 "x"
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint_fast16_t */
+#define PRIxFAST16 "x"
+
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint16_t */
+#define PRIX16 "X"
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint_least16_t */
+#define PRIXLEAST16 "X"
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint_fast16_t */
+#define PRIXFAST16 "X"
+
+
+/** \ingroup avr_inttypes
+ octal printf format for uint32_t */
+#define PRIo32 "lo"
+/** \ingroup avr_inttypes
+ octal printf format for uint_least32_t */
+#define PRIoLEAST32 "lo"
+/** \ingroup avr_inttypes
+ octal printf format for uint_fast32_t */
+#define PRIoFAST32 "lo"
+
+/** \ingroup avr_inttypes
+ decimal printf format for uint32_t */
+#define PRIu32 "lu"
+/** \ingroup avr_inttypes
+ decimal printf format for uint_least32_t */
+#define PRIuLEAST32 "lu"
+/** \ingroup avr_inttypes
+ decimal printf format for uint_fast32_t */
+#define PRIuFAST32 "lu"
+
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint32_t */
+#define PRIx32 "lx"
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint_least32_t */
+#define PRIxLEAST32 "lx"
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uint_fast32_t */
+#define PRIxFAST32 "lx"
+
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint32_t */
+#define PRIX32 "lX"
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint_least32_t */
+#define PRIXLEAST32 "lX"
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uint_fast32_t */
+#define PRIXFAST32 "lX"
+
+
+#ifdef __avr_libc_does_not_implement_long_long_in_printf_or_scanf
+
+#define PRIo64 "llo"
+#define PRIoLEAST64 "llo"
+#define PRIoFAST64 "llo"
+
+#define PRIu64 "llu"
+#define PRIuLEAST64 "llu"
+#define PRIuFAST64 "llu"
+
+#define PRIx64 "llx"
+#define PRIxLEAST64 "llx"
+#define PRIxFAST64 "llx"
+
+#define PRIX64 "llX"
+#define PRIXLEAST64 "llX"
+#define PRIXFAST64 "llX"
+
+#define PRIoMAX "llo"
+#define PRIuMAX "llu"
+#define PRIxMAX "llx"
+#define PRIXMAX "llX"
+
+#endif
+
+/** \ingroup avr_inttypes
+ octal printf format for uintptr_t */
+#define PRIoPTR PRIo16
+/** \ingroup avr_inttypes
+ decimal printf format for uintptr_t */
+#define PRIuPTR PRIu16
+/** \ingroup avr_inttypes
+ hexadecimal printf format for uintptr_t */
+#define PRIxPTR PRIx16
+/** \ingroup avr_inttypes
+ uppercase hexadecimal printf format for uintptr_t */
+#define PRIXPTR PRIX16
+
+
+#ifdef __avr_libc_does_not_implement_hh_in_scanf
+
+#define SCNd8 "hhd"
+#define SCNdLEAST8 "hhd"
+#define SCNdFAST8 "hhd"
+
+#define SCNi8 "hhi"
+#define SCNiLEAST8 "hhi"
+#define SCNiFAST8 "hhi"
+
+#endif
+
+
+/** \ingroup avr_inttypes
+ decimal scanf format for int16_t */
+#define SCNd16 "d"
+/** \ingroup avr_inttypes
+ decimal scanf format for int_least16_t */
+#define SCNdLEAST16 "d"
+/** \ingroup avr_inttypes
+ decimal scanf format for int_fast16_t */
+#define SCNdFAST16 "d"
+
+/** \ingroup avr_inttypes
+ generic-integer scanf format for int16_t */
+#define SCNi16 "i"
+/** \ingroup avr_inttypes
+ generic-integer scanf format for int_least16_t */
+#define SCNiLEAST16 "i"
+/** \ingroup avr_inttypes
+ generic-integer scanf format for int_fast16_t */
+#define SCNiFAST16 "i"
+
+
+/** \ingroup avr_inttypes
+ decimal scanf format for int32_t */
+#define SCNd32 "ld"
+/** \ingroup avr_inttypes
+ decimal scanf format for int_least32_t */
+#define SCNdLEAST32 "ld"
+/** \ingroup avr_inttypes
+ decimal scanf format for int_fast32_t */
+#define SCNdFAST32 "ld"
+
+/** \ingroup avr_inttypes
+ generic-integer scanf format for int32_t */
+#define SCNi32 "li"
+/** \ingroup avr_inttypes
+ generic-integer scanf format for int_least32_t */
+#define SCNiLEAST32 "li"
+/** \ingroup avr_inttypes
+ generic-integer scanf format for int_fast32_t */
+#define SCNiFAST32 "li"
+
+
+#ifdef __avr_libc_does_not_implement_long_long_in_printf_or_scanf
+
+#define SCNd64 "lld"
+#define SCNdLEAST64 "lld"
+#define SCNdFAST64 "lld"
+
+#define SCNi64 "lli"
+#define SCNiLEAST64 "lli"
+#define SCNiFAST64 "lli"
+
+#define SCNdMAX "lld"
+#define SCNiMAX "lli"
+
+#endif
+
+/** \ingroup avr_inttypes
+ decimal scanf format for intptr_t */
+#define SCNdPTR SCNd16
+/** \ingroup avr_inttypes
+ generic-integer scanf format for intptr_t */
+#define SCNiPTR SCNi16
+
+#ifdef __avr_libc_does_not_implement_hh_in_scanf
+
+#define SCNo8 "hho"
+#define SCNoLEAST8 "hho"
+#define SCNoFAST8 "hho"
+
+#define SCNu8 "hhu"
+#define SCNuLEAST8 "hhu"
+#define SCNuFAST8 "hhu"
+
+#define SCNx8 "hhx"
+#define SCNxLEAST8 "hhx"
+#define SCNxFAST8 "hhx"
+
+#endif
+
+/** \ingroup avr_inttypes
+ octal scanf format for uint16_t */
+#define SCNo16 "o"
+/** \ingroup avr_inttypes
+ octal scanf format for uint_least16_t */
+#define SCNoLEAST16 "o"
+/** \ingroup avr_inttypes
+ octal scanf format for uint_fast16_t */
+#define SCNoFAST16 "o"
+
+/** \ingroup avr_inttypes
+ decimal scanf format for uint16_t */
+#define SCNu16 "u"
+/** \ingroup avr_inttypes
+ decimal scanf format for uint_least16_t */
+#define SCNuLEAST16 "u"
+/** \ingroup avr_inttypes
+ decimal scanf format for uint_fast16_t */
+#define SCNuFAST16 "u"
+
+/** \ingroup avr_inttypes
+ hexadecimal scanf format for uint16_t */
+#define SCNx16 "x"
+/** \ingroup avr_inttypes
+ hexadecimal scanf format for uint_least16_t */
+#define SCNxLEAST16 "x"
+/** \ingroup avr_inttypes
+ hexadecimal scanf format for uint_fast16_t */
+#define SCNxFAST16 "x"
+
+
+/** \ingroup avr_inttypes
+ octal scanf format for uint32_t */
+#define SCNo32 "lo"
+/** \ingroup avr_inttypes
+ octal scanf format for uint_least32_t */
+#define SCNoLEAST32 "lo"
+/** \ingroup avr_inttypes
+ octal scanf format for uint_fast32_t */
+#define SCNoFAST32 "lo"
+
+/** \ingroup avr_inttypes
+ decimal scanf format for uint32_t */
+#define SCNu32 "lu"
+/** \ingroup avr_inttypes
+ decimal scanf format for uint_least32_t */
+#define SCNuLEAST32 "lu"
+/** \ingroup avr_inttypes
+ decimal scanf format for uint_fast32_t */
+#define SCNuFAST32 "lu"
+
+/** \ingroup avr_inttypes
+ hexadecimal scanf format for uint32_t */
+#define SCNx32 "lx"
+/** \ingroup avr_inttypes
+ hexadecimal scanf format for uint_least32_t */
+#define SCNxLEAST32 "lx"
+/** \ingroup avr_inttypes
+ hexadecimal scanf format for uint_fast32_t */
+#define SCNxFAST32 "lx"
+
+
+#ifdef __avr_libc_does_not_implement_long_long_in_printf_or_scanf
+
+#define SCNo64 "llo"
+#define SCNoLEAST64 "llo"
+#define SCNoFAST64 "llo"
+
+#define SCNu64 "llu"
+#define SCNuLEAST64 "llu"
+#define SCNuFAST64 "llu"
+
+#define SCNx64 "llx"
+#define SCNxLEAST64 "llx"
+#define SCNxFAST64 "llx"
+
+#define SCNoMAX "llo"
+#define SCNuMAX "llu"
+#define SCNxMAX "llx"
+
+#endif
+
+/** \ingroup avr_inttypes
+ octal scanf format for uintptr_t */
+#define SCNoPTR SCNo16
+/** \ingroup avr_inttypes
+ decimal scanf format for uintptr_t */
+#define SCNuPTR SCNu16
+/** \ingroup avr_inttypes
+ hexadecimal scanf format for uintptr_t */
+#define SCNxPTR SCNx16
+
+/* @} */
+
+
+#endif /* !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) */
+
+
+#endif /* __INTTYPES_H_ */
diff --git a/include/log.h b/include/log.h
new file mode 100644
index 0000000..f6f7193
--- /dev/null
+++ b/include/log.h
@@ -0,0 +1,63 @@
+#ifndef LOG_H
+#define LOG_H
+#include <string>
+#include <cstddef>
+
+namespace nitrokey {
+namespace log {
+
+enum class Loglevel : int {
+ DEBUG_L2,
+ DEBUG,
+ INFO,
+ WARNING,
+ ERROR
+};
+
+class LogHandler {
+public:
+ virtual void print(const std::string &, Loglevel lvl) = 0;
+
+protected:
+ std::string loglevel_to_str(Loglevel);
+};
+
+class StdlogHandler : public LogHandler {
+public:
+ 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 == NULL)
+ 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:
+ Loglevel m_loglevel;
+ LogHandler *mp_loghandler;
+
+ static Log *mp_instance;
+};
+
+}
+}
+
+#endif
diff --git a/include/misc.h b/include/misc.h
new file mode 100644
index 0000000..bf68915
--- /dev/null
+++ b/include/misc.h
@@ -0,0 +1,15 @@
+#ifndef MISC_H
+#define MISC_H
+#include <stdio.h>
+#include <string>
+
+namespace nitrokey {
+namespace misc {
+
+std::string hexdump(const char *p, size_t size);
+uint32_t stm_crc32(const uint8_t *data, size_t size);
+
+}
+}
+
+#endif
diff --git a/include/stick10_commands.h b/include/stick10_commands.h
new file mode 100644
index 0000000..de31e95
--- /dev/null
+++ b/include/stick10_commands.h
@@ -0,0 +1,582 @@
+#ifndef STICK10_COMMANDS_H
+#define STICK10_COMMANDS_H
+#include <string>
+#include <sstream>
+#include "inttypes.h"
+#include "command.h"
+
+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 & 0xF0);
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_name[15];
+
+ bool isValid() const {
+ return true;
+ }
+ } __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);
+ }
+ } __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;
+ }
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ // TODO duplicate TOTP
+ class WriteToHOTPSlot : Command<CommandID::WRITE_TO_SLOT> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint8_t slot_name[15];
+ uint8_t slot_secret[20];
+ uint8_t slot_config;
+ uint8_t slot_token_id[13];
+ uint8_t slot_counter[8];
+
+ bool isValid() const {
+ return !(slot_number & 0xF0);
+ }
+ } __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];
+ uint8_t slot_config;
+ uint8_t slot_token_id[13];
+ uint16_t slot_interval;
+
+ bool isValid() const {
+ return !(slot_number & 0xF0);
+ }
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class GetCode : 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);
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t code[18];
+
+ bool isValid() const {
+ return true;
+ }
+ } __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);
+ }
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> 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];
+ uint8_t config;
+ uint8_t token_id[13];
+ uint64_t counter;
+
+ bool isValid() const {
+ return true;
+ }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_name:\t" << slot_name << std::endl;
+ ss << "config:\t" << config << std::endl;
+ ss << "token_id:\t" << token_id << std::endl;
+ ss << "counter:\t" << counter << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct ResponsePayload> CommandTransaction;
+ };
+
+ class GetStatus : Command<CommandID::GET_STATUS> {
+ public:
+ struct ResponsePayload {
+ uint16_t firmware_version;
+ uint8_t card_serial[4];
+ uint8_t general_config[3];
+ uint8_t otp_password_config[2];
+
+ bool isValid() const {
+ return true;
+ }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "firmware_version:\t" << firmware_version << std::endl;
+ ss << "card_serial:\t"
+ << ::nitrokey::misc::hexdump((const char *)(card_serial), sizeof card_serial);
+ ss << "general_config:\t"
+ << ::nitrokey::misc::hexdump((const char *)(general_config), sizeof general_config);
+ ss << "otp_password_config:\t"
+ << ::nitrokey::misc::hexdump((const char *)(otp_password_config), sizeof otp_password_config);
+ 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;
+ }
+ } __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;
+ }
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct EmptyPayload,
+ struct ResponsePayload> CommandTransaction;
+ };
+
+ 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;
+ }
+ } __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);
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_name[PWS_SLOTNAME_LENGTH];
+
+ bool isValid() const {
+ return true;
+ }
+ } __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);
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_password[PWS_PASSWORD_LENGTH];
+
+ bool isValid() const {
+ return true;
+ }
+ } __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);
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ uint8_t slot_login[PWS_LOGINNAME_LENGTH];
+
+ bool isValid() const {
+ return true;
+ }
+ } __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);
+ }
+ } __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_name[PWS_SLOTNAME_LENGTH];
+
+ bool isValid() const {
+ return !(slot_number & 0xF0);
+ }
+ } __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);
+ }
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class EnablePasswordSafe : Command<CommandID::PW_SAFE_ENABLE> {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+
+ bool isValid() const {
+ return true;
+ }
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class PasswordSafeInitKey : Command<CommandID::PW_SAFE_INIT_KEY> {
+ public:
+ typedef Transaction<command_id(),
+ struct EmptyPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ // TODO naming screwed up, see above
+ class PasswordSafeSendSlotViaHID: Command<CommandID::PW_SAFE_SEND_DATA> {
+ 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 {
+ uint8_t config[5];
+ } __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;
+ ss << "card_password:\t" << card_password << std::endl;
+ ss << "temporary_password:\t" << temporary_password << std::endl;
+ 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;
+ }
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class Authorize : Command<CommandID::AUTHORIZE> {
+ public:
+ struct CommandPayload {
+ uint8_t crc[4];
+ uint8_t password[25];
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class UserAuthorize : Command<CommandID::USER_AUTHORIZE> {
+ public:
+ struct CommandPayload {
+ uint8_t crc[4];
+ uint8_t password[25];
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class UnlockUserPassword : Command<CommandID::UNLOCK_USER_PASSWORD> {
+ public:
+ struct CommandPayload {
+ uint8_t admin_password[20]; // TODO
+ } __packed;
+
+ // TODO could we get the stick to return the retry count?
+
+ 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];
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ // TODO why is it needed?
+ class IsAESSupported : Command<CommandID::DETECT_SC_AES> {
+ public:
+ struct CommandPayload {
+ uint8_t password[20];
+ } __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];
+ } __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 password[20];
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class BuildAESKey : Command<CommandID::NEW_AES_KEY> {
+ public:
+ struct CommandPayload {
+ uint8_t password[20];
+ } __packed;
+
+ typedef Transaction<command_id(),
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+}
+
+}
+}
+#endif
diff --git a/include/stick20_commands.h b/include/stick20_commands.h
new file mode 100644
index 0000000..22b7e9a
--- /dev/null
+++ b/include/stick20_commands.h
@@ -0,0 +1,249 @@
+#ifndef STICK20_COMMANDS_H
+#define STICK20_COMMANDS_H
+#include "inttypes.h"
+
+namespace nitrokey {
+namespace proto {
+
+/*
+* STICK20 protocol command ids
+* a superset of STICK10
+*/
+namespace stick20 {
+ class EnableEncryptedPartition : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30]; // TODO check w/ firmware
+ };
+
+ typedef Transaction<CommandID::ENABLE_CRYPTED_PARI,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class DisableEncryptedPartition : semantics::non_constructible {
+ public:
+ typedef Transaction<CommandID::DISABLE_CRYPTED_PARI,
+ struct EmptyPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class EnableHiddenEncryptedPartition : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30]; // TODO check w/ firmware
+ };
+
+ typedef Transaction<CommandID::ENABLE_HIDDEN_CRYPTED_PARI,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class DisableHiddenEncryptedPartition : semantics::non_constructible {
+ public:
+ typedef Transaction<CommandID::DISABLE_CRYPTED_PARI,
+ struct EmptyPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class EnableFirmwareUpdate : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30]; // TODO check w/ firmware
+ };
+
+ typedef Transaction<CommandID::ENABLE_FIRMWARE_UPDATE,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class UpdatePassword : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t old_password[15];
+ uint8_t new_password[15];
+ };
+
+ typedef Transaction<CommandID::CHANGE_UPDATE_PIN,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class ExportFirmware : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::EXPORT_FIRMWARE_TO_FILE,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class CreateNewKeys : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::GENERATE_NEW_KEYS,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class FillSDCardWithRandomChars : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t volume_flag;
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SetupHiddenVolume : semantics::non_constructible {
+ public:
+ typedef Transaction<CommandID::SEND_HIDDEN_VOLUME_SETUP,
+ struct EmptyPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendPasswordMatrix : semantics::non_constructible {
+ public:
+ typedef Transaction<CommandID::SEND_PASSWORD_MATRIX,
+ struct EmptyPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendPasswordMatrixPinData : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t pin_data[30]; // TODO how long actually can it be?
+ };
+
+ typedef Transaction<CommandID::SEND_PASSWORD_MATRIX_PINDATA,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendPasswordMatrixSetup : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t setup_data[30]; // TODO how long actually can it be?
+ };
+
+ typedef Transaction<CommandID::SEND_PASSWORD_MATRIX_SETUP,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class GetDeviceStatus : semantics::non_constructible {
+ public:
+ typedef Transaction<CommandID::GET_DEVICE_STATUS,
+ struct EmptyPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendPassword : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::SEND_PASSWORD,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendNewPassword : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::SEND_NEW_PASSWORD,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ // TODO fix original nomenclature
+ class SendSetReadonlyToUncryptedVolume : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendSetReadwriteToUncryptedVolume : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::ENABLE_READWRITE_UNCRYPTED_LUN,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendClearNewSdCardFound : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::CLEAR_NEW_SD_CARD_FOUND,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendStartup : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint64_t localtime; // POSIX
+ };
+
+ typedef Transaction<CommandID::SEND_STARTUP,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class SendHiddenVolumeSetup : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ // TODO HiddenVolumeSetup_tst type
+ };
+
+ typedef Transaction<CommandID::SEND_HIDDEN_VOLUME_SETUP,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class LockFirmware : semantics::non_constructible {
+ public:
+ struct CommandPayload {
+ uint8_t password[30];
+ };
+
+ typedef Transaction<CommandID::SEND_LOCK_STICK_HARDWARE,
+ struct CommandPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+ class ProductionTest : semantics::non_constructible {
+ public:
+ typedef Transaction<CommandID::PRODUCTION_TEST,
+ struct EmptyPayload,
+ struct EmptyPayload> CommandTransaction;
+ };
+
+}
+}
+}
+
+#endif
diff --git a/log.cc b/log.cc
new file mode 100644
index 0000000..cf3d8f6
--- /dev/null
+++ b/log.cc
@@ -0,0 +1,44 @@
+#include <iostream>
+#include <string>
+#include <ctime>
+#include <iomanip>
+#include "log.h"
+
+namespace nitrokey {
+namespace log {
+
+Log *Log::mp_instance = NULL;
+StdlogHandler stdlog_handler;
+
+std::string LogHandler::loglevel_to_str(Loglevel lvl) {
+ switch (lvl) {
+ case Loglevel::DEBUG_L2:
+ return std::string("DEBUG_L2");
+ case Loglevel::DEBUG:
+ return std::string("DEBUG");
+ case Loglevel::INFO:
+ return std::string("INFO");
+ case Loglevel::WARNING:
+ return std::string("WARNING");
+ case Loglevel::ERROR:
+ return std::string("ERROR");
+ }
+ return std::string("");
+}
+
+void Log::operator()(const std::string &logstr, Loglevel lvl) {
+ if (mp_loghandler != NULL)
+ if ((int)(lvl) >= (int)(m_loglevel))
+ mp_loghandler->print(logstr, lvl);
+}
+
+void StdlogHandler::print(const std::string &str, Loglevel lvl) {
+ std::time_t t = std::time(nullptr);
+ std::tm tm = *std::localtime(&t);
+
+ std::clog << "[" << loglevel_to_str(lvl) << "] ["
+ << std::put_time(&tm, "%c %Z") << "]\t" << str << std::endl;
+}
+
+}
+}
diff --git a/misc.cc b/misc.cc
new file mode 100644
index 0000000..aafa372
--- /dev/null
+++ b/misc.cc
@@ -0,0 +1,51 @@
+#include <sstream>
+#include <string>
+#include "misc.h"
+#include "inttypes.h"
+
+namespace nitrokey {
+namespace misc {
+
+std::string hexdump(const char *p, size_t size) {
+ std::stringstream out;
+ char formatbuf[128];
+ const char *pstart = p;
+
+ for (const char *pend = p + size; p < pend;) {
+ snprintf(formatbuf, 128, "%04x\t", p - pstart);
+ out << formatbuf;
+
+ for (const char *le = p + 16; p < le && p < pend; p++) {
+ snprintf(formatbuf, 128, "%02x ", uint8_t(*p));
+ out << formatbuf;
+ }
+ out << std::endl;
+ }
+ return out.str();
+}
+
+static uint32_t _crc32 (uint32_t crc, uint32_t data)
+{
+ int i;
+ crc = crc ^ data;
+
+ for (i = 0; i < 32; i++) {
+ if (crc & 0x80000000)
+ crc = (crc << 1) ^ 0x04C11DB7; // polynomial used in STM32
+ else
+ crc = (crc << 1);
+ }
+
+ return crc;
+}
+
+uint32_t stm_crc32(const uint8_t *data, size_t size) {
+ uint32_t crc = 0xffffffff;
+ const uint32_t *pend = (const uint32_t *)(data + size);
+ for (const uint32_t *p = (const uint32_t *)(data); p < pend; p++)
+ crc = _crc32(crc, *p);
+ return crc;
+}
+
+}
+}
diff --git a/test.cc b/test.cc
deleted file mode 100644
index 5c59c60..0000000
--- a/test.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <iostream>
-#include <string.h>
-#include "device_proto.h"
-#include "device.h"
-
-using namespace std;
-
-using namespace device;
-using namespace proto;
-using namespace proto::stick10::command;
-
-int main() {
- Stick20 stick;
- cout << stick.connect() << endl;
-
- {
- auto resp = GetStatus::CommandTransaction::run(stick);
- cout << resp.firmware_version << endl;
- }
-
- {
- FirstAuthenticate::CommandTransaction::CommandPayload authreq;
- strcpy((char *)(authreq.card_password), "12345678");
- FirstAuthenticate::CommandTransaction::run(stick, authreq);
- }
-
- {
- for (int i=0; i<32; i++) {
- GetSlotName::CommandTransaction::CommandPayload slotname_req;
- slotname_req.slot_number=i;
- auto slot_resp = GetSlotName::CommandTransaction::run(stick);
- cout << slot_resp.slot_name << endl;
- }
- }
-}
diff --git a/unittest/Makefile b/unittest/Makefile
new file mode 100644
index 0000000..fb3f4ef
--- /dev/null
+++ b/unittest/Makefile
@@ -0,0 +1,32 @@
+CC = $(PREFIX)-gcc
+CXX = $(PREFIX)-g++
+LD = $(CXX)
+
+INCLUDE = -I../include
+LIB = -L../build
+LDLIBS = -lhidapi-libusb -lnitrokey
+BUILD = build
+
+CXXFLAGS = -std=c++14 -fPIC
+
+CXXSOURCES = $(wildcard *.cc)
+TARGETS = $(CXXSOURCES:%.cc=$(BUILD)/%)
+DEPENDS = $(CXXSOURCES:%.cc=$(BUILD)/%.d)
+
+$(BUILD)/%.d: %.cc
+ $(CXX) -M $< -o $@ $(INCLUDE) $(CXXFLAGS)
+
+$(BUILD)/%: %.cc $(DEPENDS)
+ $(CXX) $< -o $@ $(INCLUDE) $(LIB) $(CXXFLAGS) $(LDLIBS)
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
+
+mrproper: clean
+ rm -f $(BUILD)/*.d
+
+.PHONY: all clean mrproper
+
+include $(wildcard build/*.d)
diff --git a/unittest/build/libnitrokey.so b/unittest/build/libnitrokey.so
new file mode 120000
index 0000000..69a5e22
--- /dev/null
+++ b/unittest/build/libnitrokey.so
@@ -0,0 +1 @@
+../../build/libnitrokey.so \ No newline at end of file
diff --git a/unittest/test.cc b/unittest/test.cc
new file mode 100644
index 0000000..c0762a5
--- /dev/null
+++ b/unittest/test.cc
@@ -0,0 +1,34 @@
+#include <iostream>
+#include <string.h>
+#include "device_proto.h"
+#include "log.h"
+#include "stick10_commands.h"
+
+using namespace std;
+using namespace nitrokey::device;
+using namespace nitrokey::proto::stick10;
+using namespace nitrokey::log;
+
+int main() {
+ Stick20 stick;
+
+ Log::instance().set_loglevel(Loglevel::DEBUG);
+
+ {
+ auto resp = GetStatus::CommandTransaction::run(stick);
+ }
+
+ {
+ FirstAuthenticate::CommandTransaction::CommandPayload authreq;
+ strcpy((char *)(authreq.card_password), "12345678");
+ FirstAuthenticate::CommandTransaction::run(stick, authreq);
+ }
+
+ {
+ for (int i=0; i<10; i++) {
+ ReadSlot::CommandTransaction::CommandPayload slot_req;
+ slot_req.slot_number = i;
+ auto slot = ReadSlot::CommandTransaction::run(stick, slot_req);
+ }
+ }
+}