aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/NitrokeyManager.h20
-rw-r--r--include/command_id.h2
-rw-r--r--include/device.h9
-rw-r--r--include/dissect.h59
-rw-r--r--include/stick10_commands_0.8.h312
-rw-r--r--include/stick20_commands.h10
6 files changed, 393 insertions, 19 deletions
diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h
index 60fa753..fd39445 100644
--- a/include/NitrokeyManager.h
+++ b/include/NitrokeyManager.h
@@ -5,6 +5,7 @@
#include "log.h"
#include "device_proto.h"
#include "stick10_commands.h"
+#include "stick10_commands_0.8.h"
#include "stick20_commands.h"
#include <vector>
#include <memory>
@@ -110,6 +111,12 @@ namespace nitrokey {
int get_progress_bar_value();
~NitrokeyManager();
+ bool is_authorization_command_supported();
+
+ template <typename S, typename A, typename T>
+ void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr<Device> device);
+ int get_major_firmware_version();
+
private:
NitrokeyManager();
@@ -128,6 +135,19 @@ namespace nitrokey {
template <typename ProCommand, PasswordKind StoKind>
void change_PIN_general(char *current_PIN, char *new_PIN);
+ void write_HOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret, uint64_t hotp_counter,
+ bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID,
+ const char *temporary_password);
+
+ void write_TOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret, uint16_t time_window,
+ bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID,
+ const char *temporary_password);
+
+ void write_OTP_slot_no_authorize(uint8_t internal_slot_number, const char *slot_name, const char *secret,
+ uint64_t counter_or_interval,
+ bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID,
+ const char *temporary_password) const;
+
};
}
diff --git a/include/command_id.h b/include/command_id.h
index a3806f0..346b750 100644
--- a/include/command_id.h
+++ b/include/command_id.h
@@ -65,6 +65,8 @@ enum class CommandID : uint8_t {
FACTORY_RESET = 0x13,
CHANGE_USER_PIN = 0x14,
CHANGE_ADMIN_PIN = 0x15,
+ WRITE_TO_SLOT_2 = 0x16,
+ SEND_OTP_DATA = 0x17,
ENABLE_CRYPTED_PARI = 0x20,
DISABLE_CRYPTED_PARI = 0x20 + 1, //@unused
diff --git a/include/device.h b/include/device.h
index 3f18921..62c4073 100644
--- a/include/device.h
+++ b/include/device.h
@@ -12,6 +12,15 @@ namespace nitrokey {
namespace device {
using namespace std::chrono_literals;
+ struct EnumClassHash
+ {
+ template <typename T>
+ std::size_t operator()(T t) const
+ {
+ return static_cast<std::size_t>(t);
+ }
+ };
+
enum class DeviceModel{
PRO,
STORAGE
diff --git a/include/dissect.h b/include/dissect.h
index 59e6e9c..8c975c5 100644
--- a/include/dissect.h
+++ b/include/dissect.h
@@ -36,44 +36,65 @@ class QueryDissector : semantics::non_constructible {
}
};
+
+
+
template <CommandID id, class HIDPacket>
class ResponseDissector : semantics::non_constructible {
public:
+ static std::string status_translate_device(int status){
+ auto enum_status = static_cast<proto::stick10::device_status>(status);
+ switch (enum_status){
+ case stick10::device_status::ok: return "OK";
+ case stick10::device_status::busy: return "BUSY";
+ case stick10::device_status::error: return "ERROR";
+ case stick10::device_status::received_report: return "RECEIVED_REPORT";
+ }
+ return std::string("UNKNOWN: ") + std::to_string(status);
+ }
+
+ static std::string to_upper(std::string str){
+ for (auto & c: str) c = toupper(c);
+ return str;
+ }
+ static std::string status_translate_command(int status){
+ auto enum_status = static_cast<proto::stick10::command_status >(status);
+ switch (enum_status) {
+#define p(X) case X: return to_upper(std::string(#X));
+ p(stick10::command_status::ok)
+ p(stick10::command_status::wrong_CRC)
+ p(stick10::command_status::wrong_slot)
+ p(stick10::command_status::slot_not_programmed)
+ p(stick10::command_status::wrong_password)
+ p(stick10::command_status::not_authorized)
+ p(stick10::command_status::timestamp_warning)
+ p(stick10::command_status::no_name_error)
+ p(stick10::command_status::not_supported)
+ p(stick10::command_status::unknown_command)
+ p(stick10::command_status::AES_dec_failed)
+#undef p
+ }
+ return std::string("UNKNOWN: ") + std::to_string(status);
+ }
+
static std::string dissect(const HIDPacket &pod) {
std::stringstream out;
// FIXME use values from firmware (possibly generate separate
// header automatically)
- std::string status[4];
- status[0] = " STATUS_READY";
- status[1] = " STATUS_BUSY";
- status[2] = " STATUS_ERROR";
- status[3] = " STATUS_RECEIVED_REPORT";
- std::string cmd[11];
- cmd[0] = " CMD_STATUS_OK";
- cmd[1] = " CMD_STATUS_WRONG_CRC";
- cmd[2] = " CMD_STATUS_WRONG_SLOT";
- cmd[3] = " CMD_STATUS_SLOT_NOT_PROGRAMMED";
- cmd[4] = " CMD_STATUS_WRONG_PASSWORD";
- cmd[5] = " CMD_STATUS_NOT_AUTHORIZED";
- cmd[6] = " CMD_STATUS_TIMESTAMP_WARNING";
- cmd[7] = " CMD_STATUS_NO_NAME_ERROR";
- cmd[8] = " CMD_STATUS_NOT_SUPPORTED";
- cmd[9] = " CMD_STATUS_UNKNOWN_COMMAND";
- cmd[10] = " CMD_STATUS_AES_DEC_FAILED";
out << "Raw HID packet:" << std::endl;
out << ::nitrokey::misc::hexdump((const char *)(&pod), sizeof pod);
out << "Device status:\t" << pod.device_status + 0 << " "
- << status[pod.device_status] << std::endl;
+ << status_translate_device(pod.device_status) << std::endl;
out << "Command ID:\t" << commandid_to_string((CommandID)(pod.command_id)) << " hex: " << std::hex << (int)pod.command_id
<< std::endl;
out << "Last command CRC:\t"
<< std::hex << std::setw(2) << std::setfill('0')
<< pod.last_command_crc << std::endl;
out << "Last command status:\t" << pod.last_command_status + 0 << " "
- << cmd[pod.last_command_status] << std::endl;
+ << status_translate_command(pod.last_command_status) << std::endl;
out << "CRC:\t"
<< std::hex << std::setw(2) << std::setfill('0')
<< pod.crc << std::endl;
diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h
new file mode 100644
index 0000000..9594d1e
--- /dev/null
+++ b/include/stick10_commands_0.8.h
@@ -0,0 +1,312 @@
+//
+// Created by sz on 08.11.16.
+//
+
+#ifndef LIBNITROKEY_STICK10_COMMANDS_0_8_H
+#define LIBNITROKEY_STICK10_COMMANDS_0_8_H
+
+#include <bitset>
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include "inttypes.h"
+#include "command.h"
+#include "device_proto.h"
+#include "stick10_commands.h"
+
+namespace nitrokey {
+ namespace proto {
+
+/*
+ * Stick10 protocol definition
+ */
+ namespace stick10_08 {
+ using stick10::FirstAuthenticate;
+ using stick10::UserAuthenticate;
+ using stick10::SetTime;
+ using stick10::GetStatus;
+ using stick10::BuildAESKey;
+ using stick10::ChangeAdminPin;
+ using stick10::ChangeUserPin;
+ using stick10::EnablePasswordSafe;
+ using stick10::ErasePasswordSafeSlot;
+ using stick10::FactoryReset;
+ using stick10::GetPasswordRetryCount;
+ using stick10::GetUserPasswordRetryCount;
+ using stick10::GetPasswordSafeSlotLogin;
+ using stick10::GetPasswordSafeSlotName;
+ using stick10::GetPasswordSafeSlotPassword;
+ using stick10::GetPasswordSafeSlotStatus;
+ using stick10::GetSlotName;
+ using stick10::IsAESSupported;
+ using stick10::LockDevice;
+ using stick10::PasswordSafeInitKey;
+ using stick10::PasswordSafeSendSlotViaHID;
+ using stick10::SetPasswordSafeSlotData;
+ using stick10::SetPasswordSafeSlotData2;
+ using stick10::UnlockUserPassword;
+ using stick10::ReadSlot;
+
+ class EraseSlot : Command<CommandID::ERASE_SLOT> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint8_t temporary_admin_password[25];
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+
+ class SendOTPData : Command<CommandID::SEND_OTP_DATA> {
+ //admin auth
+ public:
+ struct CommandPayload {
+ uint8_t temporary_admin_password[25];
+ uint8_t type; //S-secret, N-name
+ uint8_t id; //multiple reports for values longer than 30 bytes
+ uint8_t data[30]; //data, does not need null termination
+
+ bool isValid() const { return true; }
+
+ void setTypeName(){
+ type = 'N';
+ }
+ void setTypeSecret(){
+ type = 'S';
+ }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "temporary_admin_password:\t" << temporary_admin_password << std::endl;
+ ss << "type:\t" << type << std::endl;
+ ss << "id:\t" << (int)id << std::endl;
+ ss << "data:" << std::endl
+ << ::nitrokey::misc::hexdump((const char *) (&data), sizeof data);
+ return ss.str();
+ }
+ } __packed;
+
+
+ struct ResponsePayload {
+ union {
+ uint8_t data[40];
+ } __packed;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "data:" << std::endl
+ << ::nitrokey::misc::hexdump((const char *) (&data), sizeof data);
+ return ss.str();
+ }
+ } __packed;
+
+
+ typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
+ CommandTransaction;
+ };
+
+ class WriteToOTPSlot : Command<CommandID::WRITE_TO_SLOT> {
+ //admin auth
+ public:
+ struct CommandPayload {
+ uint8_t temporary_admin_password[25];
+ uint8_t slot_number;
+ union {
+ uint64_t slot_counter_or_interval;
+ uint8_t slot_counter_s[8];
+ } __packed;
+ union {
+ uint8_t _slot_config;
+ struct {
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ union {
+ uint8_t slot_token_id[13]; /** OATH Token Identifier */
+ struct { /** @see https://openauthentication.org/token-specs/ */
+ uint8_t omp[2];
+ uint8_t tt[2];
+ uint8_t mui[8];
+ uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
+ } slot_token_fields;
+ };
+
+ bool isValid() const { return true; }
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "temporary_admin_password:\t" << temporary_admin_password << std::endl;
+ ss << "slot_config:\t" << std::bitset<8>((int) _slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+ ss << "slot_number:\t" << (int) (slot_number) << std::endl;
+ ss << "slot_counter_or_interval:\t[" << (int) slot_counter_or_interval << "]\t"
+ << ::nitrokey::misc::hexdump((const char *) (&slot_counter_or_interval), sizeof slot_counter_or_interval, false);
+
+ ss << "slot_token_id:\t";
+ for (auto i : slot_token_id)
+ ss << std::hex << std::setw(2) << std::setfill('0') << (int) i << " ";
+ ss << std::endl;
+
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+
+ class GetHOTP : Command<CommandID::GET_CODE> {
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ struct {
+ uint64_t challenge; //@unused
+ uint64_t last_totp_time; //@unused
+ uint8_t last_interval; //@unused
+ } __packed _unused;
+ uint8_t temporary_user_password[25];
+
+ bool isValid() const { return (slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "temporary_user_password:\t" << temporary_user_password << std::endl;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ union {
+ uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
+ struct {
+ uint32_t code;
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ } __packed;
+ } __packed;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "code:\t" << (code) << std::endl;
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
+ CommandTransaction;
+ };
+
+
+ class GetTOTP : Command<CommandID::GET_CODE> {
+ //user auth
+ public:
+ struct CommandPayload {
+ uint8_t slot_number;
+ uint64_t challenge; //@unused
+ uint64_t last_totp_time; //@unused
+ uint8_t last_interval; //@unused
+ uint8_t temporary_user_password[25];
+
+ bool isValid() const { return !(slot_number & 0xF0); }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "temporary_user_password:\t" << temporary_user_password << std::endl;
+ ss << "slot_number:\t" << (int)(slot_number) << std::endl;
+ ss << "challenge:\t" << (challenge) << std::endl;
+ ss << "last_totp_time:\t" << (last_totp_time) << std::endl;
+ ss << "last_interval:\t" << (int)(last_interval) << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ struct ResponsePayload {
+ union {
+ uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
+ struct {
+ uint32_t code;
+ union{
+ uint8_t _slot_config;
+ struct{
+ bool use_8_digits : 1;
+ bool use_enter : 1;
+ bool use_tokenID : 1;
+ };
+ };
+ } __packed ;
+ } __packed ;
+
+ bool isValid() const { return true; }
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "code:\t" << (code) << std::endl;
+ ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
+ ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
+ ss << "\tuse_enter(1):\t" << use_enter << std::endl;
+ ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
+ CommandTransaction;
+ };
+
+
+ class WriteGeneralConfig : Command<CommandID::WRITE_CONFIG> {
+ //admin auth
+ public:
+ struct CommandPayload {
+ union{
+ uint8_t config[5];
+ struct{
+ uint8_t numlock; /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */
+ uint8_t capslock; /** same as numlock */
+ uint8_t scrolllock; /** same as numlock */
+ uint8_t enable_user_password;
+ uint8_t delete_user_password;
+ };
+ };
+ uint8_t temporary_admin_password[25];
+
+ std::string dissect() const {
+ std::stringstream ss;
+ ss << "numlock:\t" << (int)numlock << std::endl;
+ ss << "capslock:\t" << (int)capslock << std::endl;
+ ss << "scrolllock:\t" << (int)scrolllock << std::endl;
+ ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl;
+ ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl;
+ return ss.str();
+ }
+ } __packed;
+
+ typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
+ CommandTransaction;
+ };
+ }
+ }
+}
+#endif //LIBNITROKEY_STICK10_COMMANDS_0_8_H
diff --git a/include/stick20_commands.h b/include/stick20_commands.h
index 1af9da3..e6df770 100644
--- a/include/stick20_commands.h
+++ b/include/stick20_commands.h
@@ -125,7 +125,17 @@ namespace nitrokey {
uint16_t MagicNumber_StickConfig_u16;
uint8_t ReadWriteFlagUncryptedVolume_u8;
uint8_t ReadWriteFlagCryptedVolume_u8;
+
+ union{
uint8_t VersionInfo_au8[4];
+ struct {
+ uint8_t __unused;
+ uint8_t major;
+ uint8_t __unused2;
+ uint8_t minor;
+ } __packed versionInfo;
+ };
+
uint8_t ReadWriteFlagHiddenVolume_u8;
uint8_t FirmwareLocked_u8;
uint8_t NewSDCardFound_u8;