diff --git a/src/main.cpp b/src/main.cpp index cdf7bc7..130cc5b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,7 @@ GNU General Public License for more details. #include #include +#include #include #include #include @@ -43,6 +44,8 @@ GNU General Public License for more details. #include "scsiencrypt.h" +using namespace std::literals::string_literals; + static std::optional> key_from_hex_chars(const std::string& s) { @@ -72,21 +75,43 @@ key_from_hex_chars(const std::string& s) } // shows the command usage -static void showUsage() +static void print_usage(std::ostream& os) { - std::cerr << "Usage: stenc --version | " - "-f [--detail] [-e [-k ] " - "[-kd ] [-a ] [--protect | --unprotect] " - "[--ckod] ]\n\n" - "Type 'man stenc' for more information.\n"; -} - -// exits to shell with an error message -static void errorOut(const std::string& message) -{ - std::cerr << "Error: " << message << "\n"; - showUsage(); - exit(EXIT_FAILURE); + os << "\ +Usage: stenc [OPTION...]\n\ +\n\ +Mandatory arguments to long options are mandatory for short options too.\n\ + -f, --file=DEVICE use DEVICE as the tape drive to operate on\n\ + -e, --encrypt=ENC-MODE set encryption mode to ENC-MODE\n\ + -d, --decrypt=DEC-MODE set decryption mode to DEC-MODE\n\ + -k, --key-file=FILE read encryption key and key descriptor from FILE,\n\ + or standard input when FILE is -\n\ + -a, --algorithm=INDEX use encryption algorithm INDEX\n\ + --allow-raw-read mark written blocks to allow raw reads of\n\ + encrypted data\n\ + --no-allow-raw-read mark written blocks to disallow raw reads of\n\ + encrypted data\n\ + --ckod clear key on demount of tape media\n\ + -h, --help print this usage statement and exit\n\ + --version print version information and exit\n\ +\n\ +ENC-MODE is one of the following:\n\ + off Data written to DEVICE will not be encrypted\n\ + on Data written to DEVICE will be encrypted\n\ +\n\ +DEC-MODE is one of the following:\n\ + off Data read from DEVICE will not be decrypted and only unencrypted\n\ + records can be read.\n\ + on Data read from DEVICE will be decrypted and only encrypted records\n\ + can be read.\n\ + mixed Data read from DEVICE will be decrypted, if needed. Both encrypted\n\ + and unencrypted records can be read.\n\ +\n\ +INDEX is a number that selects the encryption algorithm and mode to use.\n\ +\n\ +When neither options to set encryption or decryption mode are given, print\n\ +encryption status and capabilities of DEVICE, including a list of supported\n\ +algorithm indexes.\n"; } static void print_algorithm_name(std::ostream& os, const uint32_t code) @@ -123,7 +148,8 @@ static void print_algorithms(std::ostream& os, const scsi::page_dec& page) for (auto ad_ptr: algorithms) { auto& ad {*ad_ptr}; - os << std::left << std::setw(5) << (unsigned int) {ad.algorithm_index}; + os << std::left << std::setw(5) + << static_cast(ad.algorithm_index); print_algorithm_name(os, ntohl(ad.security_algorithm_code)); os.put('\n'); @@ -194,91 +220,59 @@ static void inquiryDrive(const std::string& tapeDevice) print_device_inquiry(std::cout, iresult); } -static void print_device_status(std::ostream& os, const scsi::page_des& opt, - bool detail) +static void print_device_status(std::ostream& os, const scsi::page_des& opt) { - std::string emode = "unknown"; - os << std::left << std::setw(25) << "Drive Encryption:"; - if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt - opt.decryption_mode == scsi::decrypt_mode::on // read only encrypted data - ) { - emode = "on"; + os << std::left << std::setw(25) << "Drive Output:"; + switch (opt.decryption_mode) { + case scsi::decrypt_mode::off: + os << "Not decrypting\n"; + os << std::setw(25) << " " + << "Raw encrypted data not outputted\n"; + break; + case scsi::decrypt_mode::raw: + os << "Not decrypting\n"; + os << std::setw(25) << " " + << "Raw encrypted data outputted\n"; + break; + case scsi::decrypt_mode::on: + os << "Decrypting\n"; + os << std::setw(25) << " " + << "Unencrypted data not outputted\n"; + break; + case scsi::decrypt_mode::mixed: + os << "Decrypting\n"; + os << std::setw(25) << " " + << "Unencrypted data outputted\n"; + break; + default: + os << "Unknown '0x" << std::hex + << static_cast(opt.decryption_mode) << "' \n"; + break; } - if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt - opt.decryption_mode == - scsi::decrypt_mode::mixed // read encrypted and unencrypted - ) { - emode = "mixed"; + os << std::setw(25) << "Drive Input:"; + switch (opt.encryption_mode) { + case scsi::encrypt_mode::off: + os << "Not encrypting\n"; + break; + case scsi::encrypt_mode::on: + os << "Encrypting\n"; + break; + default: + os << "Unknown result '0x" << std::hex + << static_cast(opt.encryption_mode) << "'\n"; + break; + } + if ((opt.flags & scsi::page_des::flags_rdmd_mask) == + scsi::page_des::flags_rdmd_mask) { + os << std::setw(25) << " " + << "Protecting from raw read\n"; } - if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt - opt.decryption_mode == - scsi::decrypt_mode::raw // read encrypted and unencrypted - ) { - emode = "rawread"; - } - - if (opt.encryption_mode == scsi::encrypt_mode::off && // encrypt - opt.decryption_mode == - scsi::decrypt_mode::off // read encrypted and unencrypted - ) { - emode = "off"; - } - - os << emode << "\n"; - if (detail) { - os << std::left << std::setw(25) << "Drive Output:"; - switch (opt.decryption_mode) { - case scsi::decrypt_mode::off: - os << "Not decrypting\n"; - os << std::setw(25) << " " - << "Raw encrypted data not outputted\n"; - break; - case scsi::decrypt_mode::raw: - os << "Not decrypting\n"; - os << std::setw(25) << " " - << "Raw encrypted data outputted\n"; - break; - case scsi::decrypt_mode::on: - os << "Decrypting\n"; - os << std::setw(25) << " " - << "Unencrypted data not outputted\n"; - break; - case scsi::decrypt_mode::mixed: - os << "Decrypting\n"; - os << std::setw(25) << " " - << "Unencrypted data outputted\n"; - break; - default: - os << "Unknown '0x" << std::hex - << static_cast(opt.decryption_mode) << "' \n"; - break; - } - os << std::setw(25) << "Drive Input:"; - switch (opt.encryption_mode) { - case scsi::encrypt_mode::off: - os << "Not encrypting\n"; - break; - case scsi::encrypt_mode::on: - os << "Encrypting\n"; - break; - default: - os << "Unknown result '0x" << std::hex - << static_cast(opt.encryption_mode) << "'\n"; - break; - } - if ((opt.flags & scsi::page_des::flags_rdmd_mask) == - scsi::page_des::flags_rdmd_mask) { - os << std::setw(25) << " " - << "Protecting from raw read\n"; - } - - os << std::setw(25) << "Key Instance Counter:" << std::dec - << ntohl(opt.key_instance_counter) << "\n"; - if (opt.algorithm_index != 0) { - os << std::setw(25) << "Encryption Algorithm:" << std::dec - << static_cast(opt.algorithm_index) << "\n"; - } + os << std::setw(25) << "Key Instance Counter:" << std::dec + << ntohl(opt.key_instance_counter) << '\n'; + if (opt.algorithm_index != 0) { + os << std::setw(25) << "Encryption Algorithm:" << std::dec + << static_cast(opt.algorithm_index) << '\n'; } auto kads {scsi::read_page_kads(opt)}; for (auto kd: kads) { @@ -299,25 +293,24 @@ static void print_device_status(std::ostream& os, const scsi::page_des& opt, } } -static void showDriveStatus(const std::string& tapeDrive, bool detail) +static void showDriveStatus(const std::string& tapeDrive) { alignas(4) scsi::page_buffer buffer; scsi::get_des(tapeDrive, buffer, sizeof(buffer)); auto& opt {reinterpret_cast(buffer)}; - print_device_status(std::cout, opt, detail); + print_device_status(std::cout, opt); } static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt) { auto compression_status {static_cast( - (opt.status & scsi::page_nbes::status_compression_mask) >> - scsi::page_nbes::status_compression_pos)}; + opt.status & scsi::page_nbes::status_compression_mask)}; // From vendor docs, no known drives actually report anything other than 0 if (compression_status != 0u) { os << std::left << std::setw(25) << "Volume Compressed:"; switch (compression_status) { - case 0u: + case 0u << scsi::page_nbes::status_compression_pos: os << "Drive cannot determine\n"; break; default: @@ -328,28 +321,27 @@ static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt) } os << std::left << std::setw(25) << "Volume Encryption:"; auto encryption_status {static_cast( - (opt.status & scsi::page_nbes::status_encryption_mask) >> - scsi::page_nbes::status_encryption_pos)}; + opt.status & scsi::page_nbes::status_encryption_mask)}; auto kads {read_page_kads(opt)}; switch (encryption_status) { - case 0u: - case 1u: + case 0u << scsi::page_nbes::status_encryption_pos: + case 1u << scsi::page_nbes::status_encryption_pos: os << "Unable to determine\n"; break; - case 2u: + case 2u << scsi::page_nbes::status_encryption_pos: os << "Tape position not at a logical block\n"; break; - case 3u: + case 3u << scsi::page_nbes::status_encryption_pos: os << "Not encrypted\n"; break; - case 5u: + case 5u << scsi::page_nbes::status_encryption_pos: os << "Encrypted and able to decrypt\n"; if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == scsi::page_nbes::flags_rdmds_mask) { os << std::left << std::setw(25) << " Protected from raw read\n"; } break; - case 6u: + case 6u << scsi::page_nbes::status_encryption_pos: os << "Encrypted, but unable to decrypt due to invalid key.\n"; for (auto kd: kads) { switch (kd->type) { @@ -380,7 +372,7 @@ static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt) if (opt.algorithm_index != 0) { os << std::left << std::setw(25) << "Volume Algorithm:" << static_cast(opt.algorithm_index) - << "\n"; + << '\n'; } } @@ -403,103 +395,103 @@ static void echo(bool on) } #if !defined(CATCH_CONFIG_MAIN) -int main(int argc, const char **argv) +int main(int argc, char **argv) { std::string tapeDrive; - int action = 0; // 0 = status, 1 =setting param, 2 = generating key - std::string keyFile, keyDesc; - bool detail = false; + std::string keyFile; - scsi::encrypt_mode enc_mode; - scsi::decrypt_mode dec_mode; + std::optional enc_mode; + std::optional dec_mode; std::uint8_t algorithm_index; std::vector key; std::string key_name; scsi::sde_rdmc rdmc {}; bool ckod {}; - // First load all of the options - for (int i = 1; i < argc; i++) { - std::string thisCmd = argv[i]; - std::string nextCmd = ""; - if (i + 1 < argc) { - if (strncmp(argv[i + 1], "-", 1) != 0) - nextCmd = argv[i + 1]; - } - if (thisCmd == "--version") { - std::cout << "stenc v" << VERSION << " - SCSI Tape Encryption Manager\n"; - std::cout << "https://github.com/scsitape/stenc \n"; - exit(EXIT_SUCCESS); - } - if (thisCmd == "-e") { - if (nextCmd == "") { - errorOut("Key file not specified after -k option"); - } - if (nextCmd == "on") { - // encrypt, read only encrypted data - enc_mode = scsi::encrypt_mode::on; + enum opt_key : int { + opt_version = 256, + opt_ckod, + opt_rdmc_enable, + opt_rdmc_disable, + }; + + const struct option long_options[] = { + {"algorithm", required_argument, nullptr, 'a'}, + {"decrypt", required_argument, nullptr, 'd'}, + {"encrypt", required_argument, nullptr, 'e'}, + {"file", required_argument, nullptr, 'f'}, + {"key-file", required_argument, nullptr, 'k'}, + {"help", no_argument, nullptr, 'h'}, + {"ckod", no_argument, nullptr, opt_ckod}, + {"allow-raw-read", no_argument, nullptr, opt_rdmc_enable}, + {"no-allow-raw-read", no_argument, nullptr, opt_rdmc_disable}, + {"version", no_argument, nullptr, opt_version}, + {nullptr, 0, nullptr, 0}, + }; + + int opt_char; + while ((opt_char = getopt_long(argc, argv, "+a:d:e:f:k:h", long_options, + nullptr)) != -1) { + switch (opt_char) { + case 'a': + algorithm_index = std::atoi(optarg); + break; + case 'd': { + std::string arg {optarg}; + if (arg == "on"s) { dec_mode = scsi::decrypt_mode::on; - } else if (nextCmd == "mixed") { - // encrypt, read encrypted and unencrypted data - enc_mode = scsi::encrypt_mode::on; - dec_mode = scsi::decrypt_mode::mixed; - } else if (nextCmd == "rawread") { - // encrypt, read encrypted and unencrypted data - enc_mode = scsi::encrypt_mode::on; - dec_mode = scsi::decrypt_mode::raw; - } else if (nextCmd == "off") { - // encrypt, read encrypted and unencrypted data - enc_mode = scsi::encrypt_mode::off; + } else if (arg == "off"s) { dec_mode = scsi::decrypt_mode::off; + } else if (arg == "mixed"s) { + dec_mode = scsi::decrypt_mode::mixed; } else { - errorOut("Unknown encryption mode '" + nextCmd + - "'"); // encrypt, read encrypted and unencrypted data + print_usage(std::cerr); + exit(EXIT_FAILURE); } - i++; // skip the next argument - action = 1; - } else if (thisCmd == "-f") { - if (nextCmd == "") - errorOut("Device not specified after -f option."); - tapeDrive = nextCmd; // set the tape drive - i++; // skip the next argument - } else if (thisCmd == "-k") { - if (nextCmd == "") - errorOut("Key file not specified after -k option"); - keyFile = nextCmd; // set the key file - i++; // skip the next argument - } else if (thisCmd == "-kd") { - if (nextCmd == "") - errorOut("Key description not specified after the -kd option"); - keyDesc = nextCmd; // set the key file - if (keyDesc.size() > SSP_UKAD_LENGTH) { - errorOut("Key description too long!"); - } - i++; // skip the next argument - } else if (thisCmd == "--protect") { - if (rdmc == scsi::sde_rdmc::enabled) { - errorOut("'--protect' cannot be specified at the same time as " - "'--unprotect'"); - } - rdmc = scsi::sde_rdmc::disabled; - } else if (thisCmd == "--unprotect") { - if (rdmc == scsi::sde_rdmc::disabled) { - errorOut("'--unprotect' cannot be specified at the same time as " - "'--protect'"); - } - rdmc = scsi::sde_rdmc::enabled; - } else if (thisCmd == "--ckod") { - ckod = true; - } else if (thisCmd == "--detail") { - detail = true; - } else if (thisCmd == "-a") { - if (nextCmd == "") - errorOut("You must specify a numeric algorithm index when using the -a " - "flag"); - algorithm_index = std::atoi(nextCmd.c_str()); - i++; // skip the next argument - } else { - errorOut("Unknown command '" + thisCmd + "'"); + break; } + case 'e': { + std::string arg {optarg}; + if (arg == "on"s) { + enc_mode = scsi::encrypt_mode::on; + } else if (arg == "off"s) { + enc_mode = scsi::encrypt_mode::off; + } else { + print_usage(std::cerr); + exit(EXIT_FAILURE); + } + break; + } + case 'f': + tapeDrive = optarg; + break; + case 'k': + keyFile = optarg; + break; + case opt_ckod: + ckod = true; + break; + case opt_rdmc_enable: + rdmc = scsi::sde_rdmc::enabled; + break; + case opt_rdmc_disable: + rdmc = scsi::sde_rdmc::disabled; + break; + case static_cast('h'): + print_usage(std::cout); + exit(EXIT_SUCCESS); + case opt_version: + std::cout << "stenc " VERSION " - SCSI Tape Encryption Manager\n" + << "https://github.com/scsitape/stenc\n"; + exit(EXIT_SUCCESS); + default: + print_usage(std::cerr); + exit(EXIT_FAILURE); + } + } + if (optind != argc) { // left-over unparsed arguments or options + print_usage(std::cerr); + exit(EXIT_FAILURE); } // select device from env variable or system default if not given with -f @@ -511,23 +503,17 @@ int main(int argc, const char **argv) tapeDrive = DEFTAPE; } } - if (dec_mode == scsi::decrypt_mode::raw && rdmc == scsi::sde_rdmc::disabled) { - errorOut( - "'--protect' is not valid when setting encryption mode to 'rawread'"); - } openlog("stenc", LOG_CONS, LOG_USER); - if (action == 0) { - std::cout << "Status for " << tapeDrive << "\n" + if (!enc_mode && !dec_mode) { + std::cout << "Status for " << tapeDrive << '\n' << "--------------------------------------------------\n"; try { - if (detail) { - inquiryDrive(tapeDrive); - } - showDriveStatus(tapeDrive, detail); - if (detail && scsi::is_device_ready(tapeDrive)) { + inquiryDrive(tapeDrive); + showDriveStatus(tapeDrive); + if (scsi::is_device_ready(tapeDrive)) { try { showVolumeStatus(tapeDrive); } catch (const scsi::scsi_error& err) { @@ -540,98 +526,106 @@ int main(int argc, const char **argv) } } } - if (detail) { - alignas(4) scsi::page_buffer buffer {}; - scsi::get_dec(tapeDrive, buffer, sizeof(buffer)); - auto& page {reinterpret_cast(buffer)}; + alignas(4) scsi::page_buffer buffer {}; + scsi::get_dec(tapeDrive, buffer, sizeof(buffer)); + auto& page {reinterpret_cast(buffer)}; - print_algorithms(std::cout, page); - } + print_algorithms(std::cout, page); exit(EXIT_SUCCESS); } catch (const scsi::scsi_error& err) { + std::cerr << "stenc: " << err.what() << '\n'; scsi::print_sense_data(std::cerr, err.get_sense()); exit(EXIT_FAILURE); } catch (const std::runtime_error& err) { - std::cerr << err.what() << '\n'; + std::cerr << "stenc: " << err.what() << '\n'; exit(EXIT_FAILURE); } } - if (enc_mode == scsi::encrypt_mode::on) { - if (keyFile.empty()) { - std::string p1; - std::string p2; - bool done = false; - while (!done) { - std::cout << "Enter key in hex format: "; - echo(false); - getline(std::cin, p1); - echo(true); - std::cout << "\nRe-enter key in hex format: "; - echo(false); - getline(std::cin, p2); - echo(true); - std::cout << "\n"; - if (p1 != p2) { - std::cout << "Keys do not match!\n"; - } else if (p1.empty()) { - std::cout << "Key cannot be empty!\n"; - } else { - if (auto key_bytes = key_from_hex_chars(p1)) { - std::cout << "Set encryption using this key? [y/n]: "; - std::string ans = ""; - getline(std::cin, ans); - if (ans == "y") { - key = *key_bytes; - done = true; - } - } else { - std::cout << "Invalid key!\n"; - } - } - } - key_name = keyDesc; + // Infer encrypt/decrypt mode when only one is specified + if (enc_mode && !dec_mode) { + if (enc_mode == scsi::encrypt_mode::off) { + dec_mode = scsi::decrypt_mode::off; + std::cerr << "Decrypt mode not specified, using decrypt = off\n"; + } else if (enc_mode == scsi::encrypt_mode::on) { + dec_mode = scsi::decrypt_mode::on; + std::cerr << "Decrypt mode not specified, using decrypt = on\n"; } else { - // set keyInput here - std::string keyInput; - std::ifstream myfile(keyFile.c_str()); - if (myfile.is_open()) { - getline(myfile, keyInput); - getline(myfile, keyDesc); - myfile.close(); - if (auto key_bytes = key_from_hex_chars(keyInput)) { - key = *key_bytes; - } else { - errorOut("Invalid key found in '" + keyFile + "'"); - } - key_name = keyDesc; - } else - errorOut("Could not open '" + keyFile + "' for reading"); + std::cerr << "stenc: Unexpected encrypt mode " + << static_cast(*enc_mode) << '\n'; + exit(EXIT_FAILURE); + } + } else if (!enc_mode && dec_mode) { + if (dec_mode == scsi::decrypt_mode::off) { + enc_mode = scsi::encrypt_mode::off; + std::cerr << "Encrypt mode not specified, using encrypt = off\n"; + } else if (dec_mode == scsi::decrypt_mode::on || + dec_mode == scsi::decrypt_mode::mixed) { + enc_mode = scsi::encrypt_mode::on; + std::cerr << "Encrypt mode not specified, using encrypt = on\n"; + } else { + std::cerr << "stenc: Unexpected decrypt mode " + << static_cast(*dec_mode) << '\n'; + exit(EXIT_FAILURE); } } + if (enc_mode != scsi::encrypt_mode::off || + dec_mode != scsi::decrypt_mode::off) { + if (keyFile.empty()) { + std::cerr << "stenc: Encryption key required but no key file specified\n"; + exit(EXIT_FAILURE); + } + + // set keyInput here + std::string keyInput; + + if (keyFile == "-"s) { // Read key file from standard input + if (isatty(STDIN_FILENO)) { + std::cout << "Enter key (input will be hidden): "; + echo(false); + } + std::getline(std::cin, keyInput); + if (isatty(STDIN_FILENO)) { + std::cout << "\nEnter key descriptor (optional): "; + echo(true); + } + std::getline(std::cin, key_name); + } else { + std::ifstream myfile {keyFile}; + if (!myfile.is_open()) { + std::cerr << "stenc: Cannot open " << keyFile << ": " << strerror(errno) + << '\n'; + exit(EXIT_FAILURE); + } + std::getline(myfile, keyInput); + std::getline(myfile, key_name); + } + + if (auto key_bytes = key_from_hex_chars(keyInput)) { + key = *key_bytes; + } else { + std::cerr << "stenc: Invalid key in key file\n"; + exit(EXIT_FAILURE); + } + } + + if (enc_mode != scsi::encrypt_mode::on) { + key_name.erase(); // key descriptor only valid when key is used for writing + } + // Write the options to the tape device - std::cout << "Turning " - << (enc_mode != scsi::encrypt_mode::off ? "on" : "off") - << " encryption on device '" << tapeDrive << "'..." << std::endl; + std::cerr << "Changing encryption settings on device " << tapeDrive << '\n'; try { - auto sde_buffer {scsi::make_sde(enc_mode, dec_mode, algorithm_index, key, - key_name, rdmc, ckod)}; + auto sde_buffer {scsi::make_sde(enc_mode.value(), dec_mode.value(), + algorithm_index, key, key_name, rdmc, + ckod)}; scsi::write_sde(tapeDrive, sde_buffer.get()); alignas(4) scsi::page_buffer buffer {}; scsi::get_des(tapeDrive, buffer, sizeof(buffer)); auto& opt {reinterpret_cast(buffer)}; - if (enc_mode != scsi::encrypt_mode::off && - opt.encryption_mode == scsi::encrypt_mode::off) { - errorOut("Turning encryption on for '" + tapeDrive + "' failed!"); - } - if (enc_mode == scsi::encrypt_mode::off && - opt.encryption_mode != scsi::encrypt_mode::off) { - errorOut("Turning encryption off for '" + tapeDrive + "' failed!"); - } - if (enc_mode != scsi::encrypt_mode::off) { std::stringstream msg; msg << "Encryption turned on for device '" << tapeDrive << "'. "; @@ -639,7 +633,7 @@ int main(int argc, const char **argv) msg << "Key Descriptor: '" << key_name << "'"; } msg << " Key Instance: " << std::dec << ntohl(opt.key_instance_counter) - << std::endl; + << '\n'; syslog(LOG_NOTICE, "%s", msg.str().c_str()); } else { @@ -647,22 +641,18 @@ int main(int argc, const char **argv) msg << "Encryption turned off for device '" << tapeDrive << "'."; msg << " Key Instance: " << std::dec << ntohl(opt.key_instance_counter) - << std::endl; + << '\n'; syslog(LOG_NOTICE, "%s", msg.str().c_str()); } - std::cout << "Success! See system logs for a key change audit log.\n"; - exit(EXIT_SUCCESS); + std::cerr << "Success! See system logs for a key change audit log.\n"; } catch (const scsi::scsi_error& err) { + std::cerr << "stenc: " << err.what() << '\n'; scsi::print_sense_data(std::cerr, err.get_sense()); + exit(EXIT_FAILURE); } catch (const std::runtime_error& err) { - std::cerr << err.what() << '\n'; - } - - if (enc_mode != scsi::encrypt_mode::off) { - errorOut("Turning encryption on for '" + tapeDrive + "' failed!"); - } else { - errorOut("Turning encryption off for '" + tapeDrive + "' failed!"); + std::cerr << "stenc: " << err.what() << '\n'; + exit(EXIT_FAILURE); } } #endif // defined(CATCH_CONFIG_MAIN) diff --git a/src/scsiencrypt.cpp b/src/scsiencrypt.cpp index 8ed1bb1..fd66970 100644 --- a/src/scsiencrypt.cpp +++ b/src/scsiencrypt.cpp @@ -303,6 +303,9 @@ void print_sense_data(std::ostream& os, const sense_data& sd) case sense_data::no_sense: os << "No specific error"; break; + case sense_data::recovered_error: + os << "Recovered error"; + break; case sense_data::not_ready: os << "Device not ready"; break; @@ -329,10 +332,10 @@ void print_sense_data(std::ostream& os, const sense_data& sd) os << " (0x" << HEX(sense_key) << ")\n"; os << std::left << std::setw(25) << " ASC:" - << "0x" << HEX(sd.additional_sense_code) << "\n"; + << "0x" << HEX(sd.additional_sense_code) << '\n'; os << std::left << std::setw(25) << " ASCQ:" - << "0x" << HEX(sd.additional_sense_qualifier) << "\n"; + << "0x" << HEX(sd.additional_sense_qualifier) << '\n'; if (sd.additional_sense_length > 0) { os << std::left << std::setw(25) << " Additional data: " @@ -341,7 +344,7 @@ void print_sense_data(std::ostream& os, const sense_data& sd) for (int i = 0; i < sd.additional_sense_length; i++) { os << HEX(sd.additional_sense_bytes[i]); } - os << "\n"; + os << '\n'; } #ifdef DEBUGSCSI os << std::left << std::setw(25) << " Raw Sense:" @@ -351,7 +354,7 @@ void print_sense_data(std::ostream& os, const sense_data& sd) for (int i = 0; i < sense_data::maximum_size; i++) { os << HEX(rawsense[i]); } - os << "\n"; + os << '\n'; #endif } diff --git a/src/scsiencrypt.h b/src/scsiencrypt.h index cb56236..d9d1bda 100644 --- a/src/scsiencrypt.h +++ b/src/scsiencrypt.h @@ -344,7 +344,7 @@ using sense_buffer = std::array; class scsi_error : public std::runtime_error { public: explicit scsi_error(std::unique_ptr&& buf) - : sense_buf {std::move(buf)}, std::runtime_error {""} + : sense_buf {std::move(buf)}, std::runtime_error {"SCSI I/O error"} {} const sense_data& get_sense() const { diff --git a/tests/output.cpp b/tests/output.cpp index aa7cd69..c3d65e6 100644 --- a/tests/output.cpp +++ b/tests/output.cpp @@ -62,13 +62,12 @@ TEST_CASE("SCSI get device encryption status output 1", "[output]") 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const std::string expected_output {"\ -Drive Encryption: off\n\ Drive Output: Not decrypting\n\ Raw encrypted data not outputted\n\ Drive Input: Not encrypting\n\ Key Instance Counter: 0\n"s}; std::ostringstream oss; - print_device_status(oss, reinterpret_cast(page), true); + print_device_status(oss, reinterpret_cast(page)); REQUIRE(oss.str() == expected_output); } @@ -81,7 +80,6 @@ TEST_CASE("SCSI get device encryption status output 2", "[output]") 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, }; const std::string expected_output {"\ -Drive Encryption: on\n\ Drive Output: Decrypting\n\ Unencrypted data not outputted\n\ Drive Input: Encrypting\n\ @@ -89,7 +87,7 @@ Key Instance Counter: 1\n\ Encryption Algorithm: 1\n\ Drive Key Desc.(uKAD): Hello world!\n"s}; std::ostringstream oss; - print_device_status(oss, reinterpret_cast(page), true); + print_device_status(oss, reinterpret_cast(page)); REQUIRE(oss.str() == expected_output); } diff --git a/tests/scsi.cpp b/tests/scsi.cpp index 019b097..654685a 100644 --- a/tests/scsi.cpp +++ b/tests/scsi.cpp @@ -19,16 +19,16 @@ TEST_CASE("Disable encryption command", "[scsi]") { const std::uint8_t expected[] { // clang-format off - 0x00, 0x10, // page code - 0x00, 0x10, // page length - 0x40, // scope - 0x40, // CEEM, CKOD, RDMC, et al. - 0x00, // encyption mode - 0x00, // decryption mode - 0x01, // algorithm index - 0x00, // key format - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8] - 0x00, 0x00 // key length + 0x00, 0x10, // page code + 0x00, 0x10, // page length + 0x40, // scope + 0x40, // CEEM, CKOD, RDMC, et al. + 0x00, // encyption mode + 0x00, // decryption mode + 0x01, // algorithm index + 0x00, // key format + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8] + 0x00, 0x00 // key length // clang-format on }; @@ -47,20 +47,20 @@ TEST_CASE("Enable encryption command", "[scsi]") { const std::uint8_t expected[] { // clang-format off - 0x00, 0x10, // page code - 0x00, 0x30, // page length - 0x40, // scope - 0x40, // CEEM, CKOD, RDMC, et al. - 0x02, // encyption mode - 0x02, // decryption mode - 0x01, // algorithm index - 0x00, // key format - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8] - 0x00, 0x20, // key length - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x10, // page code + 0x00, 0x30, // page length + 0x40, // scope + 0x40, // CEEM, CKOD, RDMC, et al. + 0x02, // encyption mode + 0x02, // decryption mode + 0x01, // algorithm index + 0x00, // key format + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8] + 0x00, 0x20, // key length + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, // clang-format on }; @@ -83,20 +83,20 @@ TEST_CASE("Enable encryption command with options", "[scsi]") { const std::uint8_t expected[] { // clang-format off - 0x00, 0x10, // page code - 0x00, 0x30, // page length - 0x40, // scope - 0x64, // CEEM, CKOD, RDMC, et al. - 0x02, // encyption mode - 0x02, // decryption mode - 0x01, // algorithm index - 0x00, // key format - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8] - 0x00, 0x20, // key length - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x10, // page code + 0x00, 0x30, // page length + 0x40, // scope + 0x64, // CEEM, CKOD, RDMC, et al. + 0x02, // encyption mode + 0x02, // decryption mode + 0x01, // algorithm index + 0x00, // key format + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8] + 0x00, 0x20, // key length + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, // clang-format on }; @@ -119,25 +119,25 @@ TEST_CASE("Enable encryption command with key name", "[scsi]") { const std::uint8_t expected[] { // clang-format off - 0x00, 0x10, // page code - 0x00, 0x40, // page length - 0x40, // scope - 0x40, // CEEM, CKOD, RDMC, et al. - 0x02, // encyption mode - 0x02, // decryption mode - 0x01, // algorithm index - 0x00, // key format - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8] - 0x00, 0x20, // key length - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, - // KAD - 0x00, // type - 0x00, // authenticated - 0x00, 0x0c, // length - 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, + 0x00, 0x10, // page code + 0x00, 0x40, // page length + 0x40, // scope + 0x40, // CEEM, CKOD, RDMC, et al. + 0x02, // encyption mode + 0x02, // decryption mode + 0x01, // algorithm index + 0x00, // key format + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved [8] + 0x00, 0x20, // key length + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + // KAD + 0x00, // type + 0x00, // authenticated + 0x00, 0x0c, // length + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, // clang-format on }; @@ -168,23 +168,23 @@ TEST_CASE("Interpret device encryption status page", "[scsi]") { const std::uint8_t buffer[] { // clang-format off - 0x00, 0x20, // page code - 0x00, 0x24, // length - 0x42, // nexus = 2h, key scope = 2h - 0x02, // encryption mode - 0x02, // decryption mode - 0x01, // algorithm index - 0x00, 0x00, 0x00, 0x01, // key instance counter - 0x18, // parameters control = 1, VCELB = 1, CEEMS = 0, RDMD = 0 - 0x00, // KAD format - 0x00, 0x00, // ADSK count - 0x00, 0x00, 0x00, 0x00, // reserved[8] - 0x00, 0x00, 0x00, 0x00, - // KAD descriptor - 0x00, // descriptor type - 0x01, // authenticated - 0x00, 0x0c, // length - 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, + 0x00, 0x20, // page code + 0x00, 0x24, // length + 0x42, // nexus = 2h, key scope = 2h + 0x02, // encryption mode + 0x02, // decryption mode + 0x01, // algorithm index + 0x00, 0x00, 0x00, 0x01, // key instance counter + 0x18, // parameters control = 1, VCELB = 1, CEEMS = 0, RDMD = 0 + 0x00, // KAD format + 0x00, 0x00, // ADSK count + 0x00, 0x00, 0x00, 0x00, // reserved[8] + 0x00, 0x00, 0x00, 0x00, + // KAD descriptor + 0x00, // descriptor type + 0x01, // authenticated + 0x00, 0x0c, // length + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, // clang-format on }; @@ -219,18 +219,18 @@ TEST_CASE("Interpret next block encryption status page", "[scsi]") { const std::uint8_t buffer[] { // clang-format off - 0x00, 0x21, // page code - 0x00, 0x1c, // length - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x05, // compression status = 0, encryption status = 5h - 0x01, // algorithm index - 0x00, // EMES = 0, RDMDS = 0 - 0x00, // KAD format - // KAD descriptor - 0x00, // descriptor type - 0x01, // authenticated - 0x00, 0x0c, // length - 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, + 0x00, 0x21, // page code + 0x00, 0x1c, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x05, // compression status = 0, encryption status = 5h + 0x01, // algorithm index + 0x00, // EMES = 0, RDMDS = 0 + 0x00, // KAD format + // KAD descriptor + 0x00, // descriptor type + 0x01, // authenticated + 0x00, 0x0c, // length + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, // clang-format on }; @@ -259,41 +259,41 @@ TEST_CASE("Interpret data encryption capabilties page", "[scsi]") { const std::uint8_t buffer[] { // clang-format off - 0x00, 0x10, // page code - 0x00, 0x3c, // length - 0x09, // EXTDECC and CFG_P - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // algorithm 1 - 0x01, - 0x00, - 0x00, 0x14, - 0x8a, // capabilties - 0x8c, - 0x00, 0x20, - 0x00, 0x3c, - 0x00, 0x20, - 0xed, - 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x01, 0x00, 0x14, - // algorithm 2 - 0x02, - 0x00, - 0x00, 0x14, - 0x8a, // capabilties - 0x8f, - 0x00, 0x20, - 0x00, 0x3c, - 0x00, 0x20, - 0xd9, - 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x01, 0x00, 0x10, + 0x00, 0x10, // page code + 0x00, 0x3c, // length + 0x09, // EXTDECC and CFG_P + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // algorithm 1 + 0x01, + 0x00, + 0x00, 0x14, + 0x8a, // capabilties + 0x8c, + 0x00, 0x20, + 0x00, 0x3c, + 0x00, 0x20, + 0xed, + 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, 0x00, 0x14, + // algorithm 2 + 0x02, + 0x00, + 0x00, 0x14, + 0x8a, // capabilties + 0x8f, + 0x00, 0x20, + 0x00, 0x3c, + 0x00, 0x20, + 0xd9, + 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, 0x00, 0x10, // clang-format on }; static_assert(sizeof(buffer) == sizeof(scsi::page_dec) +