diff options
author | Mateusz Zalega <mateusz@appliedsourcery.com> | 2015-10-22 22:41:18 +0200 |
---|---|---|
committer | Mateusz Zalega <mateusz@appliedsourcery.com> | 2015-10-22 22:41:18 +0200 |
commit | c4aec144256e3f27fedd8f8de03e10cc08eecab8 (patch) | |
tree | e7dda787a0f98be420499a3c60f7a821d75ad60c | |
download | libnitrokey-c4aec144256e3f27fedd8f8de03e10cc08eecab8.tar.gz libnitrokey-c4aec144256e3f27fedd8f8de03e10cc08eecab8.tar.bz2 |
Initial
-rw-r--r-- | Makefile | 31 | ||||
-rw-r--r-- | crc32.cc | 37 | ||||
-rw-r--r-- | device.cc | 52 | ||||
-rw-r--r-- | include/crc32.h | 32 | ||||
-rw-r--r-- | include/cxx_semantics.h | 15 | ||||
-rw-r--r-- | include/device.h | 65 | ||||
-rw-r--r-- | include/device_proto.h | 1055 | ||||
-rw-r--r-- | test.cc | 35 |
8 files changed, 1322 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e98e631 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +CC = $(PREFIX)-gcc +CXX = $(PREFIX)-g++ +LD = $(CXX) + +INCLUDE = -Iinclude/ +LIB = -lhidapi-libusb +BUILD = build + +CXXFLAGS = -std=c++14 + +CXXSOURCES = $(wildcard *.cc) +OBJ = $(CXXSOURCES:%.cc:$(BUILD)/%.o) + +$(BUILD)/libnitrokey.so: $(OBJ) + $(CXX) -shared $(OBJ) -o $@ + +$(BUILD)/%.o: %.cc + $(CXX) -c $< -o $@ $(INCLUDE) $(CXXFLAGS) + +all: $(OBJ) $(BUILD)/libnitrokey.so + +clean: + rm $(OBJ) + rm $(BUILD)/libnitrokey.so + +mrproper: clean + rm $(BUILD)/*.d + +.PHONY: all clean mrproper + +include $(wildcard build/*.d) diff --git a/crc32.cc b/crc32.cc new file mode 100644 index 0000000..558d4ef --- /dev/null +++ b/crc32.cc @@ -0,0 +1,37 @@ +/* + * 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 new file mode 100644 index 0000000..c954cb7 --- /dev/null +++ b/device.cc @@ -0,0 +1,52 @@ +#include <chrono> +#include <thread> +#include <cstddef> +#include <hidapi/hidapi.h> +#include "device.h" + +using namespace device; + +Device::Device() +: m_vid(0), m_pid(0), + m_retry_count(4), + m_retry_timeout(50), + mp_devhandle(NULL) {} + +bool Device::connect() { + hid_init(); + + mp_devhandle = hid_open(m_vid, m_pid, NULL); + return mp_devhandle != NULL; +} + +CommError Device::send(const void *packet) { + return (CommError)( + hid_send_feature_report(mp_devhandle, (const unsigned char *)(packet), + HID_REPORT_SIZE)); +} + +CommError Device::recv(void *packet) { + CommError status; + int retry_count = 0; + + for(;;) { + status = (CommError)( + hid_get_feature_report(mp_devhandle, (unsigned char *)(packet), + HID_REPORT_SIZE)); + if (status == CommError::ERR_NO_ERROR || retry_count++ >= m_retry_count) + break; + std::this_thread::sleep_for(m_retry_timeout); + } + + return status; +} + +Stick10::Stick10() { + m_vid = 0x20a0; + m_pid = 0x4108; +} + +Stick20::Stick20() { + m_vid = 0x20a0; + m_pid = 0x4109; +} diff --git a/include/crc32.h b/include/crc32.h new file mode 100644 index 0000000..b0e16ff --- /dev/null +++ b/include/crc32.h @@ -0,0 +1,32 @@ +/* + * 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/cxx_semantics.h b/include/cxx_semantics.h new file mode 100644 index 0000000..f5d3dca --- /dev/null +++ b/include/cxx_semantics.h @@ -0,0 +1,15 @@ +#ifndef CXX_SEMANTICS_H +#define CXX_SEMANTICS_H + +#define __packed __attribute__((__packed__)) + +/* + * 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/include/device.h b/include/device.h new file mode 100644 index 0000000..b2d83b5 --- /dev/null +++ b/include/device.h @@ -0,0 +1,65 @@ +#ifndef DEVICE_H +#define DEVICE_H +#include <chrono> +#include <hidapi/hidapi.h> +#include "inttypes.h" + +#define HID_REPORT_SIZE 65 + +// TODO !! SEMAPHORE + +namespace device { +enum class CommError +{ + ERR_NO_ERROR = 0, + ERR_NOT_CONNECTED = -1, + ERR_WRONG_RESPONSE_CRC = -2, + ERR_SENDING = -3, + ERR_STATUS_NOT_OK = -4 +}; + +class Device { +public: + Device(); + + // lack of device is not actually an error, + // so it doesn't throw + virtual bool connect(); + + /* + * Sends packet of HID_REPORT_SIZE. + */ + virtual CommError send(const void *packet); + + /* + * Gets packet of HID_REPORT_SIZE. + * Can sleep. See below. + */ + virtual CommError recv(void *packet); + +protected: + uint16_t m_vid; + uint16_t m_pid; + + /* + * While the project uses Signal11 portable HIDAPI + * library, there's no way of doing it asynchronously, + * hence polling. + */ + int m_retry_count; + std::chrono::milliseconds m_retry_timeout; + + hid_device *mp_devhandle; +}; + +class Stick10 : public Device { +public: + Stick10(); +}; + +class Stick20 : public Device { +public: + Stick20(); +}; +} +#endif diff --git a/include/device_proto.h b/include/device_proto.h new file mode 100644 index 0000000..fb1dd4e --- /dev/null +++ b/include/device_proto.h @@ -0,0 +1,1055 @@ +#ifndef DEVICE_PROTO_H +#define DEVICE_PROTO_H +#include <utility> +#include <type_traits> +#include <stdexcept> +#include <string> +#include <strings.h> +// a local version for compatibility with Windows +#include "inttypes.h" +#include "cxx_semantics.h" +#include "device.h" +#include "utils/crc32.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 + +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 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. + * + * TODO (future) support for Big Endian + */ + +/* + * 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 ::crc((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(); + } +} __packed; + +/* + * Response payload (the parametrized type inside struct HIDReport) + * + * command_id member in incoming HIDReport structure carries the command + * type last used. + */ +template <typename ResponsePayload> +struct DeviceResponse { + uint8_t _zero; + uint8_t device_status; + uint8_t last_command_type; + uint32_t last_command_crc; + uint8_t last_command_status; + union { + uint8_t _padding[HID_REPORT_SIZE - 12]; + ResponsePayload payload; + } __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 ::crc((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(); + } +} __packed; + +struct EmptyPayload { + uint8_t _data[]; + + bool isValid() const { + return true; + } +} __packed; + +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<ResponsePayload> ResponsePacket; + + 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 response_payload run(device::Device &dev, + const command_payload &payload) { + using namespace device; + + CommError status; + OutgoingPacket outp; + ResponsePacket resp; + + // POD types can't have non-default constructors + outp.initialize(); + resp.initialize(); + + outp.payload = payload; + outp.update_CRC(); + + if (!outp.isValid()) + throw std::runtime_error("Invalid outgoing packet"); + + status = dev.send(&outp); + if ((int)(status) < 0 && status != CommError::ERR_NO_ERROR) + throw std::runtime_error( + std::string("Device error while sending command ") + + std::to_string((int)(status))); + + status = dev.recv(&resp); + if ((int)(status) < 0 && status != CommError::ERR_NO_ERROR) + throw std::runtime_error( + std::string("Device error while executing command ") + + std::to_string((int)(status))); + + if (!resp.isValid()) + throw std::runtime_error("Invalid incoming packet"); + + // See: DeviceResponse + return resp.payload; + } + + static response_payload run(device::Device &dev) { + command_payload empty_payload; + return run(dev, empty_payload); + } +}; + +/* + * 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 @@ -0,0 +1,35 @@ +#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; + } + } +} |