From daa541a654c1bb090323acde6b12aea413fa8747 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 1 May 2023 13:48:54 -0700 Subject: [PATCH] Update status output format (#108) * Update format of status output * Add print_buffer and modernize SCSI debug output using std::for_each --- README.md | 22 +++-- src/main.cpp | 207 ++++++++++++++++++++++++-------------------- src/scsiencrypt.cpp | 106 +++++++++++------------ src/scsiencrypt.h | 18 ++-- tests/output.cpp | 70 ++++++++++----- 5 files changed, 231 insertions(+), 192 deletions(-) diff --git a/README.md b/README.md index 159eb09..8ca13ce 100644 --- a/README.md +++ b/README.md @@ -42,19 +42,17 @@ Usage example ``` $ stenc -f /dev/nst0 -Status for /dev/nst0 +Status for /dev/nst0 (TANDBERG LTO-6 HH 3579) -------------------------------------------------- -Device Mfg: TANDBERG -Product ID: LTO-6 HH -Product Revision: 3579 -Drive Encryption: on -Drive Output: Decrypting - Unencrypted data not outputted -Drive Input: Encrypting - Protecting from raw read -Key Instance Counter: 1 -Encryption Algorithm: 1 -Drive Key Desc.(uKAD): mykey20170113 +Reading: Decrypting (AES-256-GCM-128) +Writing: Encrypting (AES-256-GCM-128) + Protecting from raw read +Key instance counter: 1 +Drive key desc. (U-KAD): mykey20170113 +Supported algorithms: +1 AES-256-GCM-128 + Key descriptors allowed, maximum 32 bytes + Raw decryption mode allowed, raw read enabled by default ``` diff --git a/src/main.cpp b/src/main.cpp index e66c448..9b1e939 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,7 @@ GNU General Public License for more details. #include #include #include +#include #include #include #include @@ -53,6 +54,8 @@ GNU General Public License for more details. using namespace std::literals::string_literals; +static const auto column_width {std::setw(33)}; + static std::optional> key_from_hex_chars(const std::string& s) { @@ -123,10 +126,12 @@ algorithm indexes.\n"; static void print_algorithm_name(std::ostream& os, const std::uint32_t code) { + auto fill {os.fill('0')}; + auto flags {os.flags(std::ios_base::hex | std::ios_base::right)}; + // Reference: SFSC / INCITS 501-2016 if (0x80010400 <= code && code <= 0x8001FFFF) { - os << "Vendor specific 0x" << std::setw(8) << std::setfill('0') << std::hex - << code << std::setfill(' '); + os << "Vendor specific 0x" << std::setw(8) << code; } switch (code) { case 0x0001000C: @@ -142,16 +147,21 @@ static void print_algorithm_name(std::ostream& os, const std::uint32_t code) os << "AES-256-XTS-HMAC-SHA-512"; break; default: - os << "Unknown 0x" << std::setw(8) << std::setfill('0') << std::hex << code - << std::setfill(' '); + os << "Unknown 0x" << std::setw(8) << code; } + + os.flags(flags); + os.fill(fill); } -static void print_algorithms(std::ostream& os, const scsi::page_dec& page) +static void print_algorithms( + std::ostream& os, + const std::vector>& + ads) { os << "Supported algorithms:\n"; - for (const scsi::algorithm_descriptor& ad: scsi::read_algorithms(page)) { + for (const scsi::algorithm_descriptor& ad: ads) { os << std::left << std::setw(5) << static_cast(ad.algorithm_index); print_algorithm_name(os, ntohl(ad.security_algorithm_code)); @@ -203,56 +213,68 @@ static void print_algorithms(std::ostream& os, const scsi::page_dec& page) } } +template +inline static void print_fixed_buffer(std::ostream& os, + const std::array buffer) +{ + // rtrim and print fixed length buffer + auto end = std::find_if(buffer.rbegin(), buffer.rend(), [](char c) { + return !std::isspace(c); + }).base(); + std::for_each(buffer.begin(), end, [&](char c) { os.put(c); }); +} + static void print_device_inquiry(std::ostream& os, const scsi::inquiry_data& iresult) { - os << std::left << std::setw(25) << "Vendor:"; - os.write(iresult.vendor, 8); - os.put('\n'); - os << std::left << std::setw(25) << "Product ID:"; - os.write(iresult.product_id, 16); - os.put('\n'); - os << std::left << std::setw(25) << "Product Revision:"; - os.write(iresult.product_rev, 4); - os.put('\n'); + print_fixed_buffer(os, iresult.vendor); + os.put(' '); + print_fixed_buffer(os, iresult.product_id); + os.put(' '); + print_fixed_buffer(os, iresult.product_rev); } -static void print_device_status(std::ostream& os, const scsi::page_des& opt) +static void +print_device_status(std::ostream& os, const scsi::page_des& opt, + const std::map& algorithms) { - os << std::left << std::setw(25) << "Drive Output:"; + os << std::left << column_width << "Reading:"; 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"; + os << "Decrypting ("; + if (algorithms.find(opt.algorithm_index) != algorithms.end()) { + os << algorithms.at(opt.algorithm_index); + } else { + os << "algorithm " << static_cast(opt.algorithm_index); + } + os << ")\n"; + if (opt.decryption_mode == scsi::decrypt_mode::on) { + os << column_width << ' ' << "Unencrypted blocks not readable\n"; + } break; default: os << "Unknown '0x" << std::hex << static_cast(opt.decryption_mode) << "' \n"; break; } - os << std::setw(25) << "Drive Input:"; + os << column_width << "Writing:"; switch (opt.encryption_mode) { case scsi::encrypt_mode::off: os << "Not encrypting\n"; break; case scsi::encrypt_mode::on: - os << "Encrypting\n"; + os << "Encrypting ("; + if (algorithms.find(opt.algorithm_index) != algorithms.end()) { + os << algorithms.at(opt.algorithm_index); + } else { + os << "algorithm " << static_cast(opt.algorithm_index); + } + os << ")\n"; break; default: os << "Unknown result '0x" << std::hex @@ -261,47 +283,29 @@ static void print_device_status(std::ostream& os, const scsi::page_des& opt) } 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 << column_width << ' ' << "Protecting from raw read\n"; } - os << std::setw(25) << "Key Instance Counter:" << std::dec + os << column_width << "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'; - } for (const scsi::kad& kd: scsi::read_page_kads(opt)) { if (kd.type == scsi::kad_type::ukad) { - os << std::setw(25) << "Drive Key Desc.(uKAD): "; + os << column_width << "Drive key desc. (U-KAD):"; os.write(reinterpret_cast(kd.descriptor), ntohs(kd.length)); os.put('\n'); } else if (kd.type == scsi::kad_type::akad) { - os << std::setw(25) << "Drive Key Desc.(aKAD): "; + os << column_width << "Drive key desc. (A-KAD):"; os.write(reinterpret_cast(kd.descriptor), ntohs(kd.length)); os.put('\n'); } } } -static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt) +static void +print_block_status(std::ostream& os, const scsi::page_nbes& opt, + const std::map& algorithms) { - auto compression_status {static_cast( - 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 << scsi::page_nbes::status_compression_pos: - os << "Drive cannot determine\n"; - break; - default: - os << "Unknown result '" << std::hex - << static_cast(compression_status) << "'\n"; - break; - } - } - os << std::left << std::setw(25) << "Volume Encryption:"; + os << std::left << column_width << "Current block status:"; auto encryption_status {static_cast( opt.status & scsi::page_nbes::status_encryption_mask)}; switch (encryption_status) { @@ -316,42 +320,49 @@ static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt) os << "Not encrypted\n"; break; case 5u << scsi::page_nbes::status_encryption_pos: - os << "Encrypted and able to decrypt\n"; + os << "Encrypted and able to decrypt ("; + if (algorithms.find(opt.algorithm_index) != algorithms.end()) { + os << algorithms.at(opt.algorithm_index); + } else { + os << "algorithm " << static_cast(opt.algorithm_index); + } + os << ")\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"; + os << std::left << column_width << ' ' << "Protected from raw read\n"; } break; case 6u << scsi::page_nbes::status_encryption_pos: - os << "Encrypted, but unable to decrypt due to invalid key.\n"; + os << "Encrypted, key missing or invalid ("; + if (algorithms.find(opt.algorithm_index) != algorithms.end()) { + os << algorithms.at(opt.algorithm_index); + } else { + os << "algorithm " << static_cast(opt.algorithm_index); + } + os << ")\n"; + if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == + scsi::page_nbes::flags_rdmds_mask) { + os << std::left << column_width << ' ' << "Protected from raw read\n"; + } for (const scsi::kad& kd: read_page_kads(opt)) { if (kd.type == scsi::kad_type::ukad) { - os << std::setw(25) << "Volume Key Desc.(uKAD): "; + os << column_width << "Current block key desc. (U-KAD):"; os.write(reinterpret_cast(kd.descriptor), ntohs(kd.length)); os.put('\n'); } else if (kd.type == scsi::kad_type::akad) { - os << std::setw(25) << "Volume Key Desc.(aKAD): "; + os << column_width << "Current block key desc. (A-KAD):"; os.write(reinterpret_cast(kd.descriptor), ntohs(kd.length)); os.put('\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; default: os << "Unknown result '" << std::hex << static_cast(encryption_status) << "'\n"; break; } - if (opt.algorithm_index != 0) { - os << std::left << std::setw(25) - << "Volume Algorithm:" << static_cast(opt.algorithm_index) - << '\n'; - } } static void echo(bool on) @@ -485,19 +496,35 @@ int main(int argc, char **argv) openlog("stenc", LOG_CONS, LOG_USER); if (!enc_mode && !dec_mode) { - std::cout << "Status for " << tapeDrive << '\n' - << "--------------------------------------------------\n"; - try { - print_device_inquiry(std::cout, scsi::get_inquiry(tapeDrive)); - scsi::get_des(tapeDrive, buffer, sizeof(buffer)); + auto inquiry_data {scsi::get_inquiry(tapeDrive)}; + std::cout << "Status for " << tapeDrive << " ("; + print_device_inquiry(std::cout, inquiry_data); + std::cout << ")\n--------------------------------------------------\n"; + + // Build map of algorithm index -> algorithm name + auto ads {scsi::read_algorithms( + scsi::get_dec(tapeDrive, buffer, sizeof(buffer)))}; + std::map algo_names; + std::for_each(ads.begin(), ads.end(), + [&algo_names](const scsi::algorithm_descriptor& ad) { + std::ostringstream oss; + print_algorithm_name(oss, + ntohl(ad.security_algorithm_code)); + algo_names[ad.algorithm_index] = oss.str(); + }); + std::ostringstream oss; + print_algorithms( + oss, ads); // save output here since buffer will be overwritten + print_device_status(std::cout, - reinterpret_cast(buffer)); + scsi::get_des(tapeDrive, buffer, sizeof(buffer)), + algo_names); if (scsi::is_device_ready(tapeDrive)) { try { - scsi::get_nbes(tapeDrive, buffer, sizeof(buffer)); - print_volume_status(std::cout, - reinterpret_cast(buffer)); + print_block_status(std::cout, + scsi::get_nbes(tapeDrive, buffer, sizeof(buffer)), + algo_names); } catch (const scsi::scsi_error& err) { // #71: ignore BLANK CHECK sense key that some drives may return // during media access check in getting NBES @@ -508,9 +535,7 @@ int main(int argc, char **argv) } } } - scsi::get_dec(tapeDrive, buffer, sizeof(buffer)); - print_algorithms(std::cout, - reinterpret_cast(buffer)); + std::cout << oss.str(); std::exit(EXIT_SUCCESS); } catch (const scsi::scsi_error& err) { std::cerr << "stenc: " << err.what() << '\n'; @@ -591,9 +616,8 @@ int main(int argc, char **argv) } try { - scsi::get_dec(tapeDrive, buffer, sizeof(buffer)); - auto& dec_page {reinterpret_cast(buffer)}; - auto algorithms {scsi::read_algorithms(dec_page)}; + auto algorithms {scsi::read_algorithms( + scsi::get_dec(tapeDrive, buffer, sizeof(buffer)))}; if (algorithm_index == std::nullopt) { if (algorithms.size() == 1) { @@ -606,7 +630,7 @@ int main(int argc, char **argv) algorithm_index = ad.algorithm_index; } else { std::cerr << "stenc: Algorithm index not specified\n"; - print_algorithms(std::cerr, dec_page); + print_algorithms(std::cerr, algorithms); std::exit(EXIT_FAILURE); } } @@ -699,17 +723,16 @@ int main(int argc, char **argv) algorithm_index.value(), key, key_name, kad_format, rdmc, ckod)}; scsi::write_sde(tapeDrive, sde_buffer.get()); - scsi::get_des(tapeDrive, buffer, sizeof(buffer)); - auto& opt {reinterpret_cast(buffer)}; + auto& opt {scsi::get_des(tapeDrive, buffer, sizeof(buffer))}; std::ostringstream oss; oss << "Encryption settings changed for device " << tapeDrive << ": mode: encrypt = " << enc_mode.value() << ", decrypt = " << dec_mode.value() << '.'; if (!key_name.empty()) { - oss << " Key Descriptor: '" << key_name << "',"; + oss << " Key descriptor: '" << key_name << "',"; } - oss << " Key Instance Counter: " << std::dec + oss << " Key instance counter: " << std::dec << ntohl(opt.key_instance_counter) << '\n'; syslog(LOG_NOTICE, "%s", oss.str().c_str()); std::cerr << "Success! See system logs for a key change audit log.\n"; diff --git a/src/scsiencrypt.cpp b/src/scsiencrypt.cpp index 2a07a0f..85d1866 100644 --- a/src/scsiencrypt.cpp +++ b/src/scsiencrypt.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. */ #include +#include #include #include #include @@ -49,10 +50,9 @@ constexpr unsigned int RETRYCOUNT {1u}; #include "scsiencrypt.h" -constexpr std::uint8_t SSP_SPIN_OPCODE = 0xa2; -constexpr std::uint8_t SSP_SPOUT_OPCODE = 0xb5; -constexpr std::uint8_t SSP_SP_CMD_LEN = 12; -constexpr std::uint8_t SSP_SP_PROTOCOL_TDE = 0x20; +constexpr std::uint8_t SSP_SPIN_OPCODE {0xa2}; +constexpr std::uint8_t SSP_SPOUT_OPCODE {0xb5}; +constexpr std::uint8_t SSP_SP_PROTOCOL_TDE {0x20}; #define BSINTTOCHAR(x) \ static_cast((x) >> 24), static_cast((x) >> 16), \ @@ -104,23 +104,33 @@ inline std::ostream& operator<<(std::ostream& os, hex h) return os; } +void print_buffer(std::ostream& os, const std::uint8_t *begin, + std::size_t length) +{ + auto fill {os.fill('0')}; + auto flags {os.flags(std::ios_base::hex | std::ios_base::right)}; + + std::for_each(begin, begin + length, [&](auto b) { + os << std::setw(2) << static_cast(b) << ' '; + }); + + os.put('\n'); + + os.flags(flags); + os.fill(fill); +} + static void scsi_execute(const std::string& device, const std::uint8_t *cmd_p, std::size_t cmd_len, std::uint8_t *dxfer_p, std::size_t dxfer_len, scsi_direction direction) { #if defined(DEBUGSCSI) std::cerr << "SCSI Command: "; - for (std::size_t i = 0; i < cmd_len; i++) { - std::cerr << hex {cmd_p[i]} << ' '; - } - std::cerr << '\n'; + print_buffer(std::cerr, cmd_p, cmd_len); if (direction == scsi_direction::to_device && dxfer_len > 0u) { std::cerr << "SCSI Data: "; - for (std::size_t i = 0; i < dxfer_len; i++) { - std::cerr << hex {dxfer_p[i]} << ' '; - } - std::cerr << '\n'; + print_buffer(std::cerr, dxfer_p, dxfer_len); } #endif @@ -204,8 +214,8 @@ bool is_device_ready(const std::string& device) } } -void get_des(const std::string& device, std::uint8_t *buffer, - std::size_t length) +const page_des& get_des(const std::string& device, std::uint8_t *buffer, + std::size_t length) { const std::uint8_t spin_des_command[] { SSP_SPIN_OPCODE, @@ -220,22 +230,19 @@ void get_des(const std::string& device, std::uint8_t *buffer, }; scsi_execute(device, spin_des_command, sizeof(spin_des_command), buffer, length, scsi_direction::from_device); + auto& page {reinterpret_cast(*buffer)}; #if defined(DEBUGSCSI) std::cerr << "SCSI Response: "; - auto& page {reinterpret_cast(*buffer)}; - std::uint8_t *it {buffer}; - const std::uint8_t *end { - buffer + std::min(length, sizeof(page_header) + ntohs(page.length))}; - while (it < end) { - std::cerr << hex {*it++} << ' '; - } - std::cerr << '\n'; + print_buffer(std::cerr, buffer, + std::min(length, sizeof(page_header) + ntohs(page.length))); #endif + + return page; } -void get_nbes(const std::string& device, std::uint8_t *buffer, - std::size_t length) +const page_nbes& get_nbes(const std::string& device, std::uint8_t *buffer, + std::size_t length) { const std::uint8_t spin_nbes_command[] { SSP_SPIN_OPCODE, @@ -250,22 +257,19 @@ void get_nbes(const std::string& device, std::uint8_t *buffer, }; scsi_execute(device, spin_nbes_command, sizeof(spin_nbes_command), buffer, length, scsi_direction::from_device); + auto& page {reinterpret_cast(*buffer)}; #if defined(DEBUGSCSI) std::cerr << "SCSI Response: "; - auto& page {reinterpret_cast(*buffer)}; - std::uint8_t *it {buffer}; - const std::uint8_t *end { - buffer + std::min(length, sizeof(page_header) + ntohs(page.length))}; - while (it < end) { - std::cerr << hex {*it++} << ' '; - } - std::cerr << '\n'; + print_buffer(std::cerr, buffer, + std::min(length, sizeof(page_header) + ntohs(page.length))); #endif + + return page; } -void get_dec(const std::string& device, std::uint8_t *buffer, - std::size_t length) +const page_dec& get_dec(const std::string& device, std::uint8_t *buffer, + std::size_t length) { const std::uint8_t spin_dec_command[] { SSP_SPIN_OPCODE, @@ -280,18 +284,15 @@ void get_dec(const std::string& device, std::uint8_t *buffer, }; scsi_execute(device, spin_dec_command, sizeof(spin_dec_command), buffer, length, scsi_direction::from_device); + auto& page {reinterpret_cast(*buffer)}; #if defined(DEBUGSCSI) std::cerr << "SCSI Response: "; - auto& page {reinterpret_cast(*buffer)}; - std::uint8_t *it {buffer}; - const std::uint8_t *end { - buffer + std::min(length, sizeof(page_header) + ntohs(page.length))}; - while (it < end) { - std::cerr << hex {*it++} << ' '; - } - std::cerr << '\n'; + print_buffer(std::cerr, buffer, + std::min(length, sizeof(page_header) + ntohs(page.length))); #endif + + return page; } inquiry_data get_inquiry(const std::string& device) @@ -306,15 +307,9 @@ inquiry_data get_inquiry(const std::string& device) #if defined(DEBUGSCSI) std::cerr << "SCSI Response: "; - std::uint8_t *it {reinterpret_cast(&inq)}; - const std::uint8_t *end { - reinterpret_cast(&inq) + - std::min(sizeof(inquiry_data), - inquiry_data::header_size + inq.additional_length)}; - while (it < end) { - std::cerr << hex {*it++} << ' '; - } - std::cerr << '\n'; + print_buffer(std::cerr, reinterpret_cast(&inq), + std::min(sizeof(inquiry_data), + inquiry_data::header_size + inq.additional_length)); #endif return inq; @@ -425,14 +420,13 @@ void print_sense_data(std::ostream& os, const sense_data& sd) << "0x" << hex {sd.additional_sense_qualifier} << '\n'; #if defined(DEBUGSCSI) - auto sense_data_length {sd.additional_sense_length + sense_data::header_size}; + auto sense_data_length { + std::min(sense_data::maximum_size, + sd.additional_sense_length + sense_data::header_size)}; auto rawsense {reinterpret_cast(&sd)}; os << std::left << std::setw(25) << " Raw sense data:"; - for (std::size_t i = 0; i < sense_data_length; i++) { - os << hex {rawsense[i]} << ' '; - } - os << '\n'; + print_buffer(os, rawsense, sense_data_length); #endif } diff --git a/src/scsiencrypt.h b/src/scsiencrypt.h index 0304bb9..11a3bb6 100644 --- a/src/scsiencrypt.h +++ b/src/scsiencrypt.h @@ -320,9 +320,9 @@ struct __attribute__((packed)) inquiry_data { std::byte flags3; std::byte flags4; std::byte flags5; - char vendor[8]; - char product_id[16]; - char product_rev[4]; + std::array vendor; + std::array product_id; + std::array product_rev; std::uint8_t vendor_specific[20]; std::byte reserved1[2]; std::uint16_t version_descriptor[8]; @@ -415,14 +415,14 @@ bool is_device_ready(const std::string& device); // Get SCSI inquiry data from device inquiry_data get_inquiry(const std::string& device); // Get data encryption status page -void get_des(const std::string& device, std::uint8_t *buffer, - std::size_t length); +const page_des& get_des(const std::string& device, std::uint8_t *buffer, + std::size_t length); // Get next block encryption status page -void get_nbes(const std::string& device, std::uint8_t *buffer, - std::size_t length); +const page_nbes& get_nbes(const std::string& device, std::uint8_t *buffer, + std::size_t length); // Get device encryption capabilities -void get_dec(const std::string& device, std::uint8_t *buffer, - std::size_t length); +const page_dec& get_dec(const std::string& device, std::uint8_t *buffer, + std::size_t length); // Fill out a set data encryption page with parameters. // Result is allocated and returned as a std::unique_ptr and should // be sent to the device using scsi::write_sde diff --git a/tests/output.cpp b/tests/output.cpp index 7a0e1fd..196aa3a 100644 --- a/tests/output.cpp +++ b/tests/output.cpp @@ -48,11 +48,7 @@ TEST_CASE("Test SCSI inquiry output", "[output]") 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; - // note: fixed width strings in output - const std::string expected_output {"\ -Vendor: ACME \n\ -Product ID: Ultrium-1000 \n\ -Product Revision: 1234\n"s}; + const std::string expected_output {"ACME Ultrium-1000 1234"s}; std::ostringstream oss; print_device_inquiry(oss, reinterpret_cast(response)); @@ -61,22 +57,27 @@ Product Revision: 1234\n"s}; TEST_CASE("SCSI get device encryption status output 1", "[output]") { + std::map algorithms { + { 1, "AES-256-GCM-128"s }, + }; const std::uint8_t page[] { 0x00, 0x20, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const std::string expected_output {"\ -Drive Output: Not decrypting\n\ - Raw encrypted data not outputted\n\ -Drive Input: Not encrypting\n\ -Key Instance Counter: 0\n"s}; +Reading: Not decrypting\n\ +Writing: Not encrypting\n\ +Key instance counter: 0\n"s}; std::ostringstream oss; - print_device_status(oss, reinterpret_cast(page)); + print_device_status(oss, reinterpret_cast(page), algorithms); REQUIRE(oss.str() == expected_output); } TEST_CASE("SCSI get device encryption status output 2", "[output]") { + std::map algorithms { + { 1, "AES-256-GCM-128"s }, + }; const std::uint8_t page[] { 0x00, 0x20, 0x00, 0x24, 0x42, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -84,42 +85,64 @@ 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 Output: Decrypting\n\ - Unencrypted data not outputted\n\ -Drive Input: Encrypting\n\ -Key Instance Counter: 1\n\ -Encryption Algorithm: 1\n\ -Drive Key Desc.(uKAD): Hello world!\n"s}; +Reading: Decrypting (AES-256-GCM-128)\n\ + Unencrypted blocks not readable\n\ +Writing: Encrypting (AES-256-GCM-128)\n\ +Key instance counter: 1\n\ +Drive key desc. (U-KAD): Hello world!\n"s}; std::ostringstream oss; - print_device_status(oss, reinterpret_cast(page)); + print_device_status(oss, reinterpret_cast(page), algorithms); REQUIRE(oss.str() == expected_output); } TEST_CASE("Test SCSI get next block encryption status output 1", "[output]") { + std::map algorithms { + { 1, "AES-256-GCM-128"s }, + }; const std::uint8_t page[] { 0x00, 0x21, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; const std::string expected_output {"\ -Volume Encryption: Not encrypted\n"s}; +Current block status: Not encrypted\n"s}; std::ostringstream oss; - print_volume_status(oss, reinterpret_cast(page)); + print_block_status(oss, reinterpret_cast(page), algorithms); REQUIRE(oss.str() == expected_output); } TEST_CASE("Test SCSI get next block encryption status output 2", "[output]") { + std::map algorithms { + { 1, "AES-256-GCM-128"s }, + }; const std::uint8_t page[] { 0x00, 0x21, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, }; const std::string expected_output {"\ -Volume Encryption: Encrypted and able to decrypt\n\ -Volume Algorithm: 1\n"s}; +Current block status: Encrypted and able to decrypt (AES-256-GCM-128)\n"s}; std::ostringstream oss; - print_volume_status(oss, reinterpret_cast(page)); + print_block_status(oss, reinterpret_cast(page), algorithms); + REQUIRE(oss.str() == expected_output); +} + +TEST_CASE("Test SCSI get next block encryption status output 3", "[output]") +{ + std::map algorithms { + { 1, "AES-256-GCM-128"s }, + }; + const std::uint8_t page[] { + 0x00, 0x21, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0c, 0x48, 0x65, + 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, + }; + const std::string expected_output {"\ +Current block status: Encrypted, key missing or invalid (AES-256-GCM-128)\n\ +Current block key desc. (U-KAD): Hello world!\n"s}; + std::ostringstream oss; + print_block_status(oss, reinterpret_cast(page), algorithms); REQUIRE(oss.str() == expected_output); } @@ -142,6 +165,7 @@ Supported algorithms:\n\ Key descriptors allowed, fixed 32 bytes\n\ Raw decryption mode allowed, raw read disabled by default\n"s}; std::ostringstream oss; - print_algorithms(oss, reinterpret_cast(page)); + print_algorithms(oss, scsi::read_algorithms( + reinterpret_cast(page))); REQUIRE(oss.str() == expected_output); }