Update status output format (#108)

* Update format of status output

* Add print_buffer and modernize SCSI debug output using std::for_each
This commit is contained in:
James Wilson
2023-05-01 13:48:54 -07:00
committed by GitHub
parent 7e449bff7b
commit daa541a654
5 changed files with 231 additions and 192 deletions

View File

@@ -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
```

View File

@@ -28,6 +28,7 @@ GNU General Public License for more details.
#include <ios>
#include <iostream>
#include <limits>
#include <map>
#include <optional>
#include <sstream>
#include <string>
@@ -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<std::vector<std::uint8_t>>
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<std::reference_wrapper<const scsi::algorithm_descriptor>>&
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<unsigned int>(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 <std::size_t N>
inline static void print_fixed_buffer(std::ostream& os,
const std::array<char, N> 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<std::uint8_t, std::string>& 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<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(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<const char *>(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<const char *>(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<std::uint8_t, std::string>& algorithms)
{
auto compression_status {static_cast<std::uint8_t>(
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<unsigned int>(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<std::uint8_t>(
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<unsigned int>(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<unsigned int>(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<const char *>(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<const char *>(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<unsigned int>(encryption_status) << "'\n";
break;
}
if (opt.algorithm_index != 0) {
os << std::left << std::setw(25)
<< "Volume Algorithm:" << static_cast<unsigned int>(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<std::uint8_t, std::string> 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<const scsi::page_des&>(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<const scsi::page_nbes&>(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<const scsi::page_dec&>(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<const scsi::page_dec&>(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<const scsi::page_des&>(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";

View File

@@ -18,6 +18,7 @@ GNU General Public License for more details.
*/
#include <config.h>
#include <algorithm>
#include <cerrno>
#include <cstring>
#include <functional>
@@ -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<std::uint8_t>((x) >> 24), static_cast<std::uint8_t>((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<unsigned int>(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<const page_des&>(*buffer)};
#if defined(DEBUGSCSI)
std::cerr << "SCSI Response: ";
auto& page {reinterpret_cast<const page_des&>(*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<const page_nbes&>(*buffer)};
#if defined(DEBUGSCSI)
std::cerr << "SCSI Response: ";
auto& page {reinterpret_cast<const page_nbes&>(*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<const page_dec&>(*buffer)};
#if defined(DEBUGSCSI)
std::cerr << "SCSI Response: ";
auto& page {reinterpret_cast<const page_dec&>(*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<std::uint8_t *>(&inq)};
const std::uint8_t *end {
reinterpret_cast<std::uint8_t *>(&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<std::uint8_t *>(&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<const std::uint8_t *>(&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
}

View File

@@ -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<char, 8> vendor;
std::array<char, 16> product_id;
std::array<char, 4> 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

View File

@@ -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<const scsi::inquiry_data&>(response));
@@ -61,22 +57,27 @@ Product Revision: 1234\n"s};
TEST_CASE("SCSI get device encryption status output 1", "[output]")
{
std::map<std::uint8_t, std::string> 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<const scsi::page_des&>(page));
print_device_status(oss, reinterpret_cast<const scsi::page_des&>(page), algorithms);
REQUIRE(oss.str() == expected_output);
}
TEST_CASE("SCSI get device encryption status output 2", "[output]")
{
std::map<std::uint8_t, std::string> 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<const scsi::page_des&>(page));
print_device_status(oss, reinterpret_cast<const scsi::page_des&>(page), algorithms);
REQUIRE(oss.str() == expected_output);
}
TEST_CASE("Test SCSI get next block encryption status output 1", "[output]")
{
std::map<std::uint8_t, std::string> 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<const scsi::page_nbes&>(page));
print_block_status(oss, reinterpret_cast<const scsi::page_nbes&>(page), algorithms);
REQUIRE(oss.str() == expected_output);
}
TEST_CASE("Test SCSI get next block encryption status output 2", "[output]")
{
std::map<std::uint8_t, std::string> 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<const scsi::page_nbes&>(page));
print_block_status(oss, reinterpret_cast<const scsi::page_nbes&>(page), algorithms);
REQUIRE(oss.str() == expected_output);
}
TEST_CASE("Test SCSI get next block encryption status output 3", "[output]")
{
std::map<std::uint8_t, std::string> 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<const scsi::page_nbes&>(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<const scsi::page_dec&>(page));
print_algorithms(oss, scsi::read_algorithms(
reinterpret_cast<const scsi::page_dec&>(page)));
REQUIRE(oss.str() == expected_output);
}