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