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:
22
README.md
22
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
|
||||
```
|
||||
|
||||
|
||||
|
||||
207
src/main.cpp
207
src/main.cpp
@@ -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";
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user