1 /*
2  * Copyright (c) 2015-2018 Nitrokey UG
3  *
4  * This file is part of libnitrokey.
5  *
6  * libnitrokey is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * any later version.
10  *
11  * libnitrokey is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
18  *
19  * SPDX-License-Identifier: LGPL-3.0
20  */
21 
22 #ifndef STICK10_COMMANDS_H
23 #define STICK10_COMMANDS_H
24 
25 #include <bitset>
26 #include <iomanip>
27 #include <string>
28 #include <sstream>
29 #include <stdint.h>
30 #include "device_proto.h"
31 #include "command.h"
32 
33 #pragma pack (push,1)
34 
35 namespace nitrokey {
36 namespace proto {
37 
38 
39 
40 /*
41  *	Stick10 protocol definition
42  */
43 namespace stick10 {
44 class GetSlotName : public Command<CommandID::READ_SLOT_NAME> {
45  public:
46   // reachable as a typedef in Transaction
47   struct CommandPayload {
48     uint8_t slot_number;
49 
isValidCommandPayload50     bool isValid() const { return slot_number<0x10+3; }
dissectCommandPayload51       std::string dissect() const {
52           std::stringstream ss;
53           ss << "slot_number:\t" << (int)(slot_number) << std::endl;
54           return ss.str();
55       }
56   } __packed;
57 
58   struct ResponsePayload {
59     uint8_t slot_name[15];
60 
isValidResponsePayload61     bool isValid() const { return true; }
dissectResponsePayload62       std::string dissect() const {
63         std::stringstream ss;
64         print_to_ss_volatile(slot_name);
65         return ss.str();
66       }
67   } __packed;
68 
69   typedef Transaction<command_id(), struct CommandPayload,
70                       struct ResponsePayload> CommandTransaction;
71 };
72 
73 class EraseSlot : Command<CommandID::ERASE_SLOT> {
74  public:
75   struct CommandPayload {
76     uint8_t slot_number;
77 
isValidCommandPayload78     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload79       std::string dissect() const {
80           std::stringstream ss;
81           ss << "slot_number:\t" << (int)(slot_number) << std::endl;
82           return ss.str();
83       }
84   } __packed;
85 
86   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
87       CommandTransaction;
88 };
89 
90 class SetTime : Command<CommandID::SET_TIME> {
91  public:
92   struct CommandPayload {
93     uint8_t reset;  // 0 - get time, 1 - set time
94     uint64_t time;  // posix time
95 
isValidCommandPayload96     bool isValid() const { return reset && reset != 1; }
dissectCommandPayload97       std::string dissect() const {
98           std::stringstream ss;
99           ss << "reset:\t" << (int)(reset) << std::endl;
100           ss << "time:\t" << (time) << std::endl;
101           return ss.str();
102       }
103   } __packed;
104 
105   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
106       CommandTransaction;
107 };
108 
109 
110 class WriteToHOTPSlot : Command<CommandID::WRITE_TO_SLOT> {
111  public:
112   struct CommandPayload {
113     uint8_t slot_number;
114     uint8_t slot_name[15];
115     uint8_t slot_secret[20];
116     union{
117       uint8_t _slot_config;
118         struct{
119             bool use_8_digits   : 1;
120             bool use_enter      : 1;
121             bool use_tokenID    : 1;
122         };
123     };
124       union{
125         uint8_t slot_token_id[13]; /** OATH Token Identifier */
126           struct{ /** @see https://openauthentication.org/token-specs/ */
127               uint8_t omp[2];
128               uint8_t tt[2];
129               uint8_t mui[8];
130               uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
131           } slot_token_fields;
132       };
133       union{
134         uint64_t slot_counter;
135         uint8_t slot_counter_s[8];
136       } __packed;
137 
isValidCommandPayload138     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload139     std::string dissect() const {
140         std::stringstream ss;
141         ss << "slot_number:\t" << (int)(slot_number) << std::endl;
142         print_to_ss_volatile(slot_name);
143         print_to_ss_volatile(slot_secret);
144         ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
145         ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
146         ss << "\tuse_enter(1):\t" << use_enter << std::endl;
147         ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
148 
149         ss << "slot_token_id:\t";
150         for (auto i : slot_token_id)
151             ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
152         ss << std::endl;
153         ss << "slot_counter:\t[" << (int)slot_counter << "]\t"
154          << ::nitrokey::misc::hexdump((const uint8_t *)(&slot_counter), sizeof slot_counter, false);
155 
156       return ss.str();
157     }
158   } __packed;
159 
160   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
161       CommandTransaction;
162 };
163 
164 class WriteToTOTPSlot : Command<CommandID::WRITE_TO_SLOT> {
165  public:
166   struct CommandPayload {
167     uint8_t slot_number;
168     uint8_t slot_name[15];
169     uint8_t slot_secret[20];
170       union{
171           uint8_t _slot_config;
172           struct{
173               bool use_8_digits   : 1;
174               bool use_enter      : 1;
175               bool use_tokenID    : 1;
176           };
177       };
178       union{
179           uint8_t slot_token_id[13]; /** OATH Token Identifier */
180           struct{ /** @see https://openauthentication.org/token-specs/ */
181               uint8_t omp[2];
182               uint8_t tt[2];
183               uint8_t mui[8];
184               uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
185           } slot_token_fields;
186       };
187     uint16_t slot_interval;
188 
isValidCommandPayload189     bool isValid() const { return !(slot_number & 0xF0); } //TODO check
dissectCommandPayload190       std::string dissect() const {
191           std::stringstream ss;
192           ss << "slot_number:\t" << (int)(slot_number) << std::endl;
193           print_to_ss_volatile(slot_name);
194           print_to_ss_volatile(slot_secret);
195           ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
196           ss << "slot_token_id:\t";
197           for (auto i : slot_token_id)
198               ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
199           ss << std::endl;
200           ss << "slot_interval:\t" << (int)slot_interval << std::endl;
201           return ss.str();
202       }
203   } __packed;
204 
205   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
206       CommandTransaction;
207 };
208 
209 class GetTOTP : Command<CommandID::GET_CODE> {
210  public:
211   struct CommandPayload {
212     uint8_t slot_number;
213     uint64_t challenge;
214     uint64_t last_totp_time;
215     uint8_t last_interval;
216 
isValidCommandPayload217     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload218     std::string dissect() const {
219       std::stringstream ss;
220       ss << "slot_number:\t" << (int)(slot_number) << std::endl;
221       ss << "challenge:\t" << (challenge) << std::endl;
222       ss << "last_totp_time:\t" << (last_totp_time) << std::endl;
223       ss << "last_interval:\t" << (int)(last_interval) << std::endl;
224       return ss.str();
225     }
226   } __packed;
227 
228   struct ResponsePayload {
229       union {
230           uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
231           struct {
232               uint32_t code;
233               union{
234                   uint8_t _slot_config;
235                   struct{
236                       bool use_8_digits   : 1;
237                       bool use_enter      : 1;
238                       bool use_tokenID    : 1;
239                   };
240               };
241           } __packed ;
242       } __packed ;
243 
isValidResponsePayload244     bool isValid() const { return true; }
dissectResponsePayload245     std::string dissect() const {
246       std::stringstream ss;
247       ss << "code:\t" << (code) << std::endl;
248         ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
249         ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
250         ss << "\tuse_enter(1):\t" << use_enter << std::endl;
251         ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
252       return ss.str();
253     }
254   } __packed;
255 
256   typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
257       CommandTransaction;
258 };
259 
260 class GetHOTP : Command<CommandID::GET_CODE> {
261  public:
262   struct CommandPayload {
263     uint8_t slot_number;
264 
isValidCommandPayload265     bool isValid() const { return (slot_number & 0xF0); }
dissectCommandPayload266     std::string dissect() const {
267       std::stringstream ss;
268       ss << "slot_number:\t" << (int)(slot_number) << std::endl;
269       return ss.str();
270     }
271   } __packed;
272 
273   struct ResponsePayload {
274       union {
275           uint8_t whole_response[18]; //14 bytes reserved for config, but used only 1
276           struct {
277               uint32_t code;
278               union{
279                   uint8_t _slot_config;
280                   struct{
281                       bool use_8_digits   : 1;
282                       bool use_enter      : 1;
283                       bool use_tokenID    : 1;
284                   };
285               };
286           } __packed;
287       } __packed;
288 
isValidResponsePayload289     bool isValid() const { return true; }
dissectResponsePayload290     std::string dissect() const {
291       std::stringstream ss;
292       ss << "code:\t" << (code) << std::endl;
293         ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
294         ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
295         ss << "\tuse_enter(1):\t" << use_enter << std::endl;
296         ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
297       return ss.str();
298     }
299   } __packed;
300 
301   typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>
302       CommandTransaction;
303 };
304 
305 class ReadSlot : Command<CommandID::READ_SLOT> {
306  public:
307   enum class CounterFormat {
308     ASCII = 0,
309     BINARY = 1,
310   };
311   struct CommandPayload {
312     uint8_t slot_number;
313     CounterFormat data_format; //Storage v0.54+ only: slot_counter value format: 0 - in ascii, 1 - binary
314 
isValidCommandPayload315     bool isValid() const { return !(slot_number & 0xF0); }
316 
dissectCommandPayload317     std::string dissect() const {
318       std::stringstream ss;
319       ss << "slot_number:\t" << (int)(slot_number) << std::endl;
320       return ss.str();
321     }
322   } __packed;
323 
324   struct ResponsePayload {
325     uint8_t slot_name[15];
326     union{
327       uint8_t _slot_config;
328       struct{
329         bool use_8_digits   : 1;
330         bool use_enter      : 1;
331         bool use_tokenID    : 1;
332       };
333     };
334     union{
335       uint8_t slot_token_id[13]; /** OATH Token Identifier */
336       struct{ /** @see https://openauthentication.org/token-specs/ */
337         uint8_t omp[2];
338         uint8_t tt[2];
339         uint8_t mui[8];
340         uint8_t keyboard_layout; //disabled feature in nitroapp as of 20160805
341       } slot_token_fields;
342     };
343     union{
344       uint64_t slot_counter;
345       uint8_t slot_counter_s[8];
346     } __packed;
347 
isValidResponsePayload348     bool isValid() const { return true; }
349 
dissectResponsePayload350     std::string dissect() const {
351       std::stringstream ss;
352       print_to_ss_volatile(slot_name);
353       ss << "slot_config:\t" << std::bitset<8>((int)_slot_config) << std::endl;
354       ss << "\tuse_8_digits(0):\t" << use_8_digits << std::endl;
355       ss << "\tuse_enter(1):\t" << use_enter << std::endl;
356       ss << "\tuse_tokenID(2):\t" << use_tokenID << std::endl;
357 
358       ss << "slot_token_id:\t";
359       for (auto i : slot_token_id)
360         ss << std::hex << std::setw(2) << std::setfill('0')<< (int) i << " " ;
361       ss << std::endl;
362       ss << "slot_counter:\t[" << (int)slot_counter << "]\t"
363          << ::nitrokey::misc::hexdump((const uint8_t *)(&slot_counter), sizeof slot_counter, false);
364       return ss.str();
365     }
366   } __packed;
367 
368   typedef Transaction<command_id(), struct CommandPayload,
369                       struct ResponsePayload> CommandTransaction;
370 };
371 
372 class GetStatus : Command<CommandID::GET_STATUS> {
373  public:
374   struct ResponsePayload {
375     union {
376       uint16_t firmware_version;
377       struct {
378         uint8_t minor;
379         uint8_t major;
380       } firmware_version_st;
381     };
382     union{
383       uint8_t card_serial[4];
384       uint32_t card_serial_u32;
385     } __packed;
386       union {
387           uint8_t general_config[5];
388           struct{
389               uint8_t numlock;     /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */
390               uint8_t capslock;    /** same as numlock */
391               uint8_t scrolllock;  /** same as numlock */
392               uint8_t enable_user_password;
393               uint8_t delete_user_password; /* unused */
394           } __packed;
395       } __packed;
396 
397     static constexpr uint8_t special_HOTP_slots = 2;
isValidResponsePayload398     bool isValid() const { return numlock < special_HOTP_slots && capslock < special_HOTP_slots
399                                   && scrolllock < special_HOTP_slots && enable_user_password < 2; }
400 
get_card_serial_hexResponsePayload401     std::string get_card_serial_hex() const {
402       return nitrokey::misc::toHex(card_serial_u32);
403     }
404 
dissectResponsePayload405     std::string dissect() const {
406       std::stringstream ss;
407       ss  << "firmware_version:\t"
408           << "[" << firmware_version << "]" << "\t"
409           << ::nitrokey::misc::hexdump(
410           (const uint8_t *)(&firmware_version), sizeof firmware_version, false);
411       ss << "card_serial_u32:\t" << std::hex << card_serial_u32 << std::endl;
412       ss << "card_serial:\t"
413          << ::nitrokey::misc::hexdump((const uint8_t *)(card_serial),
414                                       sizeof card_serial, false);
415       ss << "general_config:\t"
416          << ::nitrokey::misc::hexdump((const uint8_t *)(general_config),
417                                       sizeof general_config, false);
418         ss << "numlock:\t" << (int)numlock << std::endl;
419         ss << "capslock:\t" << (int)capslock << std::endl;
420         ss << "scrolllock:\t" << (int)scrolllock << std::endl;
421         ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl;
422         ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl;
423 
424         return ss.str();
425     }
426   } __packed;
427 
428   typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
429       CommandTransaction;
430 };
431 
432 class GetPasswordRetryCount : Command<CommandID::GET_PASSWORD_RETRY_COUNT> {
433  public:
434   struct ResponsePayload {
435     uint8_t password_retry_count;
436 
isValidResponsePayload437     bool isValid() const { return true; }
dissectResponsePayload438     std::string dissect() const {
439       std::stringstream ss;
440       ss << " password_retry_count\t" << (int)password_retry_count << std::endl;
441       return ss.str();
442     }
443   } __packed;
444 
445   typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
446       CommandTransaction;
447 };
448 
449 class GetUserPasswordRetryCount
450     : Command<CommandID::GET_USER_PASSWORD_RETRY_COUNT> {
451  public:
452   struct ResponsePayload {
453     uint8_t password_retry_count;
454 
isValidResponsePayload455     bool isValid() const { return true; }
dissectResponsePayload456     std::string dissect() const {
457       std::stringstream ss;
458       ss << " password_retry_count\t" << (int)password_retry_count << std::endl;
459       return ss.str();
460     }
461   } __packed;
462 
463   typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
464       CommandTransaction;
465 };
466 
467     template <typename T, typename Q, int N>
write_array(T & ss,Q (& arr)[N])468     void write_array(T &ss, Q (&arr)[N]){
469         for (int i=0; i<N; i++){
470             ss << std::hex << std::setfill('0') << std::setw(2) << (int)arr[i] << " ";
471         }
472         ss << std::endl;
473     };
474 
475 
476 class GetPasswordSafeSlotStatus : Command<CommandID::GET_PW_SAFE_SLOT_STATUS> {
477  public:
478   struct ResponsePayload {
479     uint8_t password_safe_status[PWS_SLOT_COUNT];
480 
isValidResponsePayload481     bool isValid() const { return true; }
dissectResponsePayload482       std::string dissect() const {
483           std::stringstream ss;
484           ss << "password_safe_status\t";
485           write_array(ss, password_safe_status);
486           return ss.str();
487       }
488   } __packed;
489 
490   typedef Transaction<command_id(), struct EmptyPayload, struct ResponsePayload>
491       CommandTransaction;
492 };
493 
494 class GetPasswordSafeSlotName : Command<CommandID::GET_PW_SAFE_SLOT_NAME> {
495  public:
496   struct CommandPayload {
497     uint8_t slot_number;
498 
isValidCommandPayload499     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload500     std::string dissect() const {
501       std::stringstream ss;
502       ss << "slot_number\t" << (int)slot_number << std::endl;
503       return ss.str();
504     }
505   } __packed;
506 
507   struct ResponsePayload {
508     uint8_t slot_name[PWS_SLOTNAME_LENGTH];
509 
isValidResponsePayload510     bool isValid() const { return true; }
dissectResponsePayload511     std::string dissect() const {
512       std::stringstream ss;
513       print_to_ss_volatile(slot_name);
514       return ss.str();
515     }
516   } __packed;
517 
518   typedef Transaction<command_id(), struct CommandPayload,
519                       struct ResponsePayload> CommandTransaction;
520 };
521 
522 class GetPasswordSafeSlotPassword
523     : Command<CommandID::GET_PW_SAFE_SLOT_PASSWORD> {
524  public:
525   struct CommandPayload {
526     uint8_t slot_number;
527 
isValidCommandPayload528     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload529     std::string dissect() const {
530       std::stringstream ss;
531       ss << "   slot_number\t" << (int)slot_number << std::endl;
532       return ss.str();
533     }
534   } __packed;
535 
536   struct ResponsePayload {
537     uint8_t slot_password[PWS_PASSWORD_LENGTH];
538 
isValidResponsePayload539     bool isValid() const { return true; }
dissectResponsePayload540     std::string dissect() const {
541       std::stringstream ss;
542       print_to_ss_volatile(slot_password);
543       return ss.str();
544     }
545   } __packed;
546 
547   typedef Transaction<command_id(), struct CommandPayload,
548                       struct ResponsePayload> CommandTransaction;
549 };
550 
551 class GetPasswordSafeSlotLogin
552     : Command<CommandID::GET_PW_SAFE_SLOT_LOGINNAME> {
553  public:
554   struct CommandPayload {
555     uint8_t slot_number;
556 
isValidCommandPayload557     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload558     std::string dissect() const {
559       std::stringstream ss;
560       ss << "   slot_number\t" << (int)slot_number << std::endl;
561       return ss.str();
562     }
563   } __packed;
564 
565   struct ResponsePayload {
566     uint8_t slot_login[PWS_LOGINNAME_LENGTH];
567 
isValidResponsePayload568     bool isValid() const { return true; }
dissectResponsePayload569     std::string dissect() const {
570       std::stringstream ss;
571       print_to_ss_volatile(slot_login);
572       return ss.str();
573     }
574   } __packed;
575 
576   typedef Transaction<command_id(), struct CommandPayload,
577                       struct ResponsePayload> CommandTransaction;
578 };
579 
580 class SetPasswordSafeSlotData : Command<CommandID::SET_PW_SAFE_SLOT_DATA_1> {
581  public:
582   struct CommandPayload {
583     uint8_t slot_number;
584     uint8_t slot_name[PWS_SLOTNAME_LENGTH];
585     uint8_t slot_password[PWS_PASSWORD_LENGTH];
586 
isValidCommandPayload587     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload588       std::string dissect() const {
589           std::stringstream ss;
590           ss << " slot_number\t" << (int)slot_number << std::endl;
591           print_to_ss_volatile(slot_name);
592           print_to_ss_volatile(slot_password);
593           return ss.str();
594       }
595   } __packed;
596 
597   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
598       CommandTransaction;
599 };
600 
601 class SetPasswordSafeSlotData2 : Command<CommandID::SET_PW_SAFE_SLOT_DATA_2> {
602  public:
603   struct CommandPayload {
604     uint8_t slot_number;
605     uint8_t slot_login_name[PWS_LOGINNAME_LENGTH];
606 
isValidCommandPayload607     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload608       std::string dissect() const {
609         std::stringstream ss;
610         ss << " slot_number\t" << (int)slot_number << std::endl;
611         print_to_ss_volatile(slot_login_name);
612         return ss.str();
613       }
614   } __packed;
615 
616   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
617       CommandTransaction;
618 };
619 
620 class ErasePasswordSafeSlot : Command<CommandID::PW_SAFE_ERASE_SLOT> {
621  public:
622   struct CommandPayload {
623     uint8_t slot_number;
624 
isValidCommandPayload625     bool isValid() const { return !(slot_number & 0xF0); }
dissectCommandPayload626       std::string dissect() const {
627           std::stringstream ss;
628           ss << " slot_number\t" << (int)slot_number << std::endl;
629           return ss.str();
630       }
631 
632   } __packed;
633 
634   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
635       CommandTransaction;
636 };
637 
638 class EnablePasswordSafe : Command<CommandID::PW_SAFE_ENABLE> {
639  public:
640   struct CommandPayload {
641     uint8_t user_password[30];
642 
isValidCommandPayload643     bool isValid() const { return true; }
dissectCommandPayload644     std::string dissect() const {
645       std::stringstream ss;
646       print_to_ss_volatile(user_password);
647       return ss.str();
648     }
649   } __packed;
650 
651   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
652       CommandTransaction;
653 };
654 
655 class PasswordSafeInitKey : Command<CommandID::PW_SAFE_INIT_KEY> {
656     /**
657      * never used in Nitrokey App
658      */
659  public:
660   typedef Transaction<command_id(), struct EmptyPayload, struct EmptyPayload>
661       CommandTransaction;
662 };
663 
664 class PasswordSafeSendSlotViaHID : Command<CommandID::PW_SAFE_SEND_DATA> {
665     /**
666      * never used in Nitrokey App
667      */
668  public:
669   struct CommandPayload {
670     uint8_t slot_number;
671     uint8_t slot_kind;
672 
isValidCommandPayload673     bool isValid() const { return !(slot_number & 0xF0); }
674   } __packed;
675 
676   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
677       CommandTransaction;
678 };
679 
680 // TODO "Device::passwordSafeSendSlotDataViaHID"
681 
682 class WriteGeneralConfig : Command<CommandID::WRITE_CONFIG> {
683  public:
684   struct CommandPayload {
685     union{
686         uint8_t config[5];
687         struct{
688             uint8_t numlock;     /** 0-1: HOTP slot number from which the code will be get on double press, other value - function disabled */
689             uint8_t capslock;    /** same as numlock */
690             uint8_t scrolllock;  /** same as numlock */
691             uint8_t enable_user_password;
692             uint8_t delete_user_password;
693         };
694     };
isValidCommandPayload695     bool isValid() const { return numlock < 2 && capslock < 2 && scrolllock < 2 && enable_user_password < 2; }
696 
dissectCommandPayload697     std::string dissect() const {
698           std::stringstream ss;
699           ss << "numlock:\t" << (int)numlock << std::endl;
700           ss << "capslock:\t" << (int)capslock << std::endl;
701           ss << "scrolllock:\t" << (int)scrolllock << std::endl;
702           ss << "enable_user_password:\t" << (bool) enable_user_password << std::endl;
703           ss << "delete_user_password:\t" << (bool) delete_user_password << std::endl;
704           return ss.str();
705       }
706   } __packed;
707 
708   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
709       CommandTransaction;
710 };
711 
712 class FirstAuthenticate : Command<CommandID::FIRST_AUTHENTICATE> {
713  public:
714   struct CommandPayload {
715     uint8_t card_password[25];
716     uint8_t temporary_password[25];
717 
isValidCommandPayload718     bool isValid() const { return true; }
719 
dissectCommandPayload720     std::string dissect() const {
721       std::stringstream ss;
722       print_to_ss_volatile(card_password);
723       hexdump_to_ss(temporary_password);
724       return ss.str();
725     }
726   } __packed;
727 
728   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
729       CommandTransaction;
730 };
731 
732 class UserAuthenticate : Command<CommandID::USER_AUTHENTICATE> {
733  public:
734   struct CommandPayload {
735     uint8_t card_password[25];
736     uint8_t temporary_password[25];
737 
isValidCommandPayload738     bool isValid() const { return true; }
dissectCommandPayload739       std::string dissect() const {
740         std::stringstream ss;
741         print_to_ss_volatile(card_password);
742         hexdump_to_ss(temporary_password);
743         return ss.str();
744       }
745   } __packed;
746 
747   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
748       CommandTransaction;
749 };
750 
751 class Authorize : Command<CommandID::AUTHORIZE> {
752  public:
753   struct CommandPayload {
754     uint32_t crc_to_authorize;
755     uint8_t temporary_password[25];
756 
dissectCommandPayload757       std::string dissect() const {
758       std::stringstream ss;
759       ss << " crc_to_authorize:\t" << std::hex << std::setw(2) << std::setfill('0') << crc_to_authorize<< std::endl;
760       hexdump_to_ss(temporary_password);
761       return ss.str();
762     }
763   } __packed;
764 
765   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
766       CommandTransaction;
767 };
768 
769 class UserAuthorize : Command<CommandID::USER_AUTHORIZE> {
770  public:
771   struct CommandPayload {
772     uint32_t crc_to_authorize;
773     uint8_t temporary_password[25];
dissectCommandPayload774     std::string dissect() const {
775       std::stringstream ss;
776       ss << " crc_to_authorize:\t" <<  crc_to_authorize<< std::endl;
777       hexdump_to_ss(temporary_password);
778       return ss.str();
779     }
780   } __packed;
781 
782   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
783       CommandTransaction;
784 };
785 
786 class UnlockUserPassword : Command<CommandID::UNLOCK_USER_PASSWORD> {
787  public:
788   struct CommandPayload {
789     uint8_t admin_password[25];
790     uint8_t user_new_password[25];
dissectCommandPayload791       std::string dissect() const {
792         std::stringstream ss;
793         print_to_ss_volatile(admin_password);
794         print_to_ss_volatile(user_new_password);
795         return ss.str();
796       }
797   } __packed;
798 
799   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
800       CommandTransaction;
801 };
802 
803 class ChangeUserPin : Command<CommandID::CHANGE_USER_PIN> {
804  public:
805   struct CommandPayload {
806     uint8_t old_pin[25];
807     uint8_t new_pin[25];
dissectCommandPayload808       std::string dissect() const {
809         std::stringstream ss;
810         print_to_ss_volatile(old_pin);
811         print_to_ss_volatile(new_pin);
812         return ss.str();
813       }
814   } __packed;
815 
816   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
817       CommandTransaction;
818 };
819 
820 class IsAESSupported : Command<CommandID::DETECT_SC_AES> {
821  public:
822   struct CommandPayload {
823     uint8_t user_password[20];
dissectCommandPayload824       std::string dissect() const {
825         std::stringstream ss;
826         print_to_ss_volatile(user_password);
827         return ss.str();
828       }
829   } __packed;
830 
831   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
832       CommandTransaction;
833 };
834 
835 
836 class ChangeAdminPin : Command<CommandID::CHANGE_ADMIN_PIN> {
837  public:
838   struct CommandPayload {
839     uint8_t old_pin[25];
840     uint8_t new_pin[25];
dissectCommandPayload841       std::string dissect() const {
842         std::stringstream ss;
843         print_to_ss_volatile(old_pin);
844         print_to_ss_volatile(new_pin);
845         return ss.str();
846       }
847   } __packed;
848 
849   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
850       CommandTransaction;
851 };
852 
853 class LockDevice : Command<CommandID::LOCK_DEVICE> {
854  public:
855   typedef Transaction<command_id(), struct EmptyPayload, struct EmptyPayload>
856       CommandTransaction;
857 };
858 
859 class FactoryReset : Command<CommandID::FACTORY_RESET> {
860  public:
861   struct CommandPayload {
862     uint8_t admin_password[20];
dissectCommandPayload863       std::string dissect() const {
864         std::stringstream ss;
865         print_to_ss_volatile(admin_password);
866         return ss.str();
867       }
868   } __packed;
869 
870   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
871       CommandTransaction;
872 };
873 
874 class BuildAESKey : Command<CommandID::NEW_AES_KEY> {
875  public:
876   struct CommandPayload {
877     uint8_t admin_password[20];
dissectCommandPayload878       std::string dissect() const {
879         std::stringstream ss;
880         print_to_ss_volatile(admin_password);
881         return ss.str();
882       }
883   } __packed;
884 
885   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
886       CommandTransaction;
887 
888 };
889 
890 class FirmwareUpdate : Command<CommandID::FIRMWARE_UPDATE> {
891 public:
892   struct CommandPayload {
893     uint8_t firmware_password[20];
dissectCommandPayload894     std::string dissect() const {
895       std::stringstream ss;
896       print_to_ss_volatile(firmware_password);
897       return ss.str();
898       }
899   } __packed;
900 
901   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
902     CommandTransaction;
903 
904 };
905 
906 class FirmwarePasswordChange : Command<CommandID::FIRMWARE_PASSWORD_CHANGE> {
907 public:
908   struct CommandPayload {
909     uint8_t firmware_password_current[20];
910     uint8_t firmware_password_new[20];
dissectCommandPayload911     std::string dissect() const {
912       std::stringstream ss;
913       print_to_ss_volatile(firmware_password_current);
914       print_to_ss_volatile(firmware_password_new);
915       return ss.str();
916     }
917   } __packed;
918 
919   typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload>
920     CommandTransaction;
921 
922 };
923 
924 
925 }
926 }
927 }
928 #pragma pack (pop)
929 #endif
930